package com.itlong.cloud.property.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.itlong.cloud.POJO.DTO.property.AppUserDelInvitedAuthDTO;
import com.itlong.cloud.POJO.DTO.property.PropertyEquipAuthGetDTO;
import com.itlong.cloud.POJO.DTO.property.UserDeviceAuthAddreddDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardSyncDataPullDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardSyncDataTmpAuthDTO;
import com.itlong.cloud.POJO.PO.*;
import com.itlong.cloud.POJO.VO.app.AppDoorDevicesVO;
import com.itlong.cloud.POJO.VO.app.AppFloorDevicesVO;
import com.itlong.cloud.POJO.VO.property.*;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.app.service.IAppDeviceService;
import com.itlong.cloud.constants.RabbitMQConstant;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.*;
import com.itlong.cloud.property.dao.*;
import com.itlong.cloud.property.service.IPropertyDeviceAuthService;
import com.itlong.cloud.property.service.IPropertyEquipService;
import com.itlong.cloud.rabbitmq.config.MessageSender;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.smartcard.dao.ISmartCardFaceDao;
import com.itlong.cloud.smartcard.service.ISmartCardFaceService;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.date.DateUtil;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <desc>
 *      操作用户设备权限接口实现类
 * </desc>
 *
 * @createDate 2017-11-02
 */
@Service
public class PropertyDeviceAuthServiceImpl implements IPropertyDeviceAuthService{

    private static final Logger LOG = LoggerFactory.getLogger(PropertyDeviceAuthServiceImpl.class);

    //设备权限服务层线程连接池
    private static ExecutorService deviceAuthServiceThreadPool = Executors.newFixedThreadPool(16);

    @Autowired
    private IPropertyEquipService iPropertyEquipService;

    @Autowired
    private IPropertyDeviceAuthElevatorAuthDao iPropertyDeviceAuthElevatorAuthDao;

    @Autowired
    private IPropertyDeviceAuthEntranceAuthDao iPropertyDeviceAuthEntranceAuthDao;

    @Autowired
    private IPropertyDeviceAuthCloudIntercomAuthDao iPropertyDeviceAuthCloudIntercomAuthDao;

    @Autowired
    ISmartCardFaceDao iSmartCardFaceDao;

    @Autowired
    private RedisService<AppUserGetDeviceAuthVO> redisService;     //redis访问对象

    @Autowired
    private MessageSender messageSender;

    @Autowired
    IAppDeviceService iAppDeviceService;

    @Autowired
    ISmartCardFaceService iSmartCardFaceService;

    @Autowired
    private ITimeTaskAuthDeviceAddressInfoDao iTimeTaskAuthDeviceAddressInfoDao;

    @Autowired
    private IPadFaceSyncDataServiceDao iPadFaceSyncDataServiceDao;

    private static final int DEVICEAUTH_DEVICETYPE_ELEVATOR = 1;     //电梯设备类型
    private static final int DEVICEAUTH_DEVICETYPE_ENTRANCE = 2;     //门禁设备类型
    private static final int DEVICEAUTH_DEVICETYPE_CLOUDINTERCOM = 3;    //云对讲设备类型

    /**
     * <desc>
     *      合成并保存受设备地址变更影响的住户设备权限
     * <desc/>
     * @param userDeviceAuthAddreddDTOS  地址信息集
     * @param authSource  权限来源
     * @return
     * @author zhangs
     * @createDate 2017/11/2
     */
    @Override
//    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveUserAuthByAddr(List<UserDeviceAuthAddreddDTO> userDeviceAuthAddreddDTOS, Integer authSource) throws Exception {
        if(userDeviceAuthAddreddDTOS == null || (userDeviceAuthAddreddDTOS != null && userDeviceAuthAddreddDTOS.size() < 1)) {
            return;
        }
        //记录需要通知App模块刷新以及与旺龙一卡通对接的用户Id
        List<RecordAppUserIdAndProjectIdVO> recordUserAndProjectIds = new ArrayList<>();
        for(UserDeviceAuthAddreddDTO userDeviceAuthAddreddDTO : userDeviceAuthAddreddDTOS) {
            String projectId = userDeviceAuthAddreddDTO.getProjectId();
            String authUserId = userDeviceAuthAddreddDTO.getAuthUserId();
            String userId = userDeviceAuthAddreddDTO.getUserId();

            recordUserAndProjectIds.add(new RecordAppUserIdAndProjectIdVO(userId, projectId));

            //用户拥有的房间地址集合 eg:{"buildId001":{"unitId01":"1001,1301","unitId03":"0703,0905"}}
            Map<String, Object> userAuthRoomAddrMap = userDeviceAuthAddreddDTO.getUserAuthRoomAddrMap();
            if (userAuthRoomAddrMap == null) {
                //住户在当前小区地址全为迁出则清除住户在当前小区的所有设备权限
                this.deleteUserDeviceAuth(null, userId, projectId, null);
            } else {
                AppUserDeviceAuthsVO appUserDeviceAuthsVO = iPropertyEquipService.getEquipByAddress(userDeviceAuthAddreddDTO);
                List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = appUserDeviceAuthsVO.getAppUserGetDeviceAuthVOS();
                if(appUserGetDeviceAuthVOS != null && appUserGetDeviceAuthVOS.size() > 0) {
                    //更新源于物业系统地址的用户设备权限
                    this.updateUserDeviceAuth(authUserId, userId, projectId, appUserGetDeviceAuthVOS, authSource);
                } else {
                    //若地址下无对应设备则删掉对应来源的设备权限
                    this.deleteUserDeviceAuth(authUserId, userId, projectId, DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType());
                }
            }
        }
        if (recordUserAndProjectIds.size() > 0) {
            for (RecordAppUserIdAndProjectIdVO recordAppUserIdAndProjectIdVO:recordUserAndProjectIds) {
                String userId = recordAppUserIdAndProjectIdVO.getUserId();
                String projectId = recordAppUserIdAndProjectIdVO.getProjectId();
                updateUserDeviceAuthAtRedis(userId, projectId,true, null);
            }
        }
    }

    /**
     * <desc>
     *      分类处理住户设备权限
     * <desc/>
     * @param userDeviceAuthAddreddDTOS  需额外删除的被邀请而被赋予权限的二级用户map
     * @param userDeviceAuthAddreddDTOS  地址信息集
     * @param authSource  权限来源
     * @param jPushMessage  极光推送信息
     * @return
     * @author zhangs
     * @createDate 2018/1/18
     */
    @Override
    public void classifyUserDeviceAuth(
            Map<String, AppUserDelInvitedAuthDTO> delInvitedAuthDTOMap,
            List<UserDeviceAuthAddreddDTO> userDeviceAuthAddreddDTOS,
            Integer authSource,
            String jPushMessage) throws Exception {
        if(userDeviceAuthAddreddDTOS == null || (userDeviceAuthAddreddDTOS != null && userDeviceAuthAddreddDTOS.size() < 1)) {
            return;
        }
        for (UserDeviceAuthAddreddDTO userDeviceAuthAddreddDTO : userDeviceAuthAddreddDTOS) {
            String projectId = userDeviceAuthAddreddDTO.getProjectId();
            String authUserId = userDeviceAuthAddreddDTO.getAuthUserId();
            String userId = userDeviceAuthAddreddDTO.getUserId();
            //用户拥有的房间地址集合 eg:{"buildId001":{"unitId01":"1001,1301","unitId03":"0703,0905"}}
            Map<String, Object> userAuthRoomAddrMap = userDeviceAuthAddreddDTO.getUserAuthRoomAddrMap();
            if (userAuthRoomAddrMap == null) {
                //住户在当前小区地址全为迁出则清除住户在当前小区的所有设备权限
                this.deleteUserPropertyDeviceAuth(null, userId, projectId, authSource, jPushMessage);
            } else {
                AppUserDeviceAuthsVO appUserDeviceAuthsVO = iPropertyEquipService.getEquipByAddress(userDeviceAuthAddreddDTO);
                List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = appUserDeviceAuthsVO.getAppUserGetDeviceAuthVOS();
                if(appUserGetDeviceAuthVOS != null && appUserGetDeviceAuthVOS.size() > 0) {
                    //删除二级用户被邀请而得到的设备权限
                    if (delInvitedAuthDTOMap != null) {
                        AppUserDelInvitedAuthDTO appUserDelInvitedAuthDTO = delInvitedAuthDTOMap.get(userId);
                        if (appUserDelInvitedAuthDTO != null) {
                            String parentUserId = appUserDelInvitedAuthDTO.getParentUserId();
                            this.delInvitedAuth(parentUserId, userId, projectId);
                        }
                    }
                    //更新用户的非临时设备权限
                    this.updateUserDeviceAuth(authUserId, userId, projectId, appUserGetDeviceAuthVOS, authSource, jPushMessage);
                } else {
                    //若地址下无对应设备则删掉对应来源的设备权限
                    //权限来源于物业
                    this.deleteUserPropertyDeviceAuth(authUserId, userId, projectId, DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType(), jPushMessage);
                    //权限来源于App
                    this.deleteUserPropertyDeviceAuth(null, userId, projectId, DeviceAuthEnum.DEVICEAUTH_APP.getType(), jPushMessage);
                }
            }
        }
    }

    /**
     * <desc>
     *      删除二级住户被邀请而获得的设备权限
     * <desc/>
     * @param parentUserId  父级用户Id
     * @param userId  用户Id
     * @param projectId  项目Id
     * @return
     * @author zhangs
     * @createDate 2018/1/18
     */
    private void delInvitedAuth(String parentUserId, String userId, String projectId) {
        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        param.put("authUserId", parentUserId);
        param.put("authSource", DeviceAuthEnum.DEVICEAUTH_APP.getType());
        //清除住户在当前小区的电梯设备权限
        iPropertyDeviceAuthElevatorAuthDao.delByParam(param);

        //清除住户在当前小区的门禁设备权限
        iPropertyDeviceAuthEntranceAuthDao.delByParam(param);

        //清除住户在当前小区的云对讲设备权限
        iPropertyDeviceAuthCloudIntercomAuthDao.delByParam(param);
    }

    /**
     * <desc>
     *      物业地址授权-更新用户设备权限
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @param authSource  权限来源
     * @param jPushMessage  极光推送信息
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    public void updateUserDeviceAuth (
            String authUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS,
            Integer authSource,
            String jPushMessage) throws Exception{
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) || appUserGetDeviceAuthVOS.size() == 0) {
            return ;
        }

        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        param.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            param.put("authUserId", authUserId);
        }

        //更新或清除用户设备权限(电梯/门禁/云对讲)
        this.updateOrDelUserDeviceAuthToDB(appUserGetDeviceAuthVOS, authUserId, userId, projectId, authSource, param);

        //更新用户的授权来源为App的权限。迁出住户受邀请获得的房间时应更改授权来源是App的权限。
        // (appUserGetDeviceAuthVOS中存储用户当前最新的设备权限,若不在该集合中的权限则需去掉)
        if (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType() && authSource != DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType()) {
            this.updateUserDeviceAuthAtApp(userId, projectId, appUserGetDeviceAuthVOS);
        }

        //更新redis中的用户设备权限
        try {
            updateUserDeviceAuthAtRedis(userId, projectId,true, jPushMessage);
        } catch (Exception e) {
            LOG.error(String.format("【物业系统_更新redis中用户设备权限信息出错_updateUserDeviceAuthAtRedis()】" +
                    "info:{%s, %s}", userId, projectId), e);
        }
    }

    /**
     * <desc>
     *      更新用户的授权来源为App的权限
     *      appUserGetDeviceAuthVOS中存储用户当前最新的设备权限,若不在该集合中的权限则需去掉，反之不处理
     * <desc/>
     * @param userId  用户Id
     * @param projectId  项目Id
     * @param appUserGetDeviceAuthVOS  用户设备权限信息
     * @return
     * @author zhangs
     * @createDate 2018/1/18
     */
//    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateUserDeviceAuthAtApp(String userId, String projectId, List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS) throws Exception {
        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        param.put("authSource", DeviceAuthEnum.DEVICEAUTH_APP.getType());

        //获取用户旧的来源为App的设备权限信息(电梯/门禁/云对讲)
        List<DeviceElevatorAuthPO> deviceElevatorAuthPOS = iPropertyDeviceAuthElevatorAuthDao.getUserDeviceElevatorAuth(param);
        List<DeviceEntranceAuthPO> deviceEntranceAuthPOS = iPropertyDeviceAuthEntranceAuthDao.getUserDeviceEntranceAuth(param);
        List<DeviceCloudIntercomAuthPO> deviceCloudIntercomAuthPOS =
                iPropertyDeviceAuthCloudIntercomAuthDao.getUserDeviceCloudIntercomAuth(param);

        if (appUserGetDeviceAuthVOS != null && appUserGetDeviceAuthVOS.size()  > 0) {
            //将用户最新的设备权限分类，提取有权限码的位置
            List<Integer> elevatorPositionAtAuth = new ArrayList<>();
            List<String> naturalFloorList = new ArrayList<>();
            List<Integer> entrancePositionAtAuth = new ArrayList<>();
            List<Integer> cloudIntercomPositionAtAuth = new ArrayList<>();
            for (AppUserGetDeviceAuthVO appUserGetDeviceAuthVO:appUserGetDeviceAuthVOS) {
                String deviceType = appUserGetDeviceAuthVO.getDeviceType();
                String deviceUnique = appUserGetDeviceAuthVO.getDeviceUnique();
                //获取设备机号
                String deviceId = StringHandlerUtil.copySubStr(deviceUnique, 9, 4);
                if (!StringUtils.isNumeric(deviceId)) {
                    continue;
                }
                //设备在权限码deviceAuth中的位置
                Integer devicePositionAtAuth = Integer.parseInt(deviceId) - 1;
                if (StringHandlerUtil.compareStrWithOutEmpty(deviceType, String.valueOf(PropertyEquipTypeEnum.ELEVATOR.getType()))) {
                    elevatorPositionAtAuth.add(devicePositionAtAuth);
                    naturalFloorList.add(appUserGetDeviceAuthVO.getNaturalFloor());
                } else if (StringHandlerUtil.compareStrWithOutEmpty(deviceType, String.valueOf(PropertyEquipTypeEnum.ENTRANCE.getType()))) {
                    entrancePositionAtAuth.add(devicePositionAtAuth);
                } else if (StringHandlerUtil.compareStrWithOutEmpty(deviceType, String.valueOf(PropertyEquipTypeEnum.CLOUD_INTERCOM.getType()))) {
                    cloudIntercomPositionAtAuth.add(devicePositionAtAuth);
                }
            }

            /*将用户最新的设备权限与旧的来源为App的权限比较(权限码位置比较)，新的包含旧的除电梯外不处理(电梯中还需处理楼层权限)，
            * 旧的不在新的中则去除，新的中有但旧的中没有则均不出来
            * */
            if (((elevatorPositionAtAuth.size() > 0) && (naturalFloorList.size() > 0)) &&
                    (deviceElevatorAuthPOS != null && deviceElevatorAuthPOS.size() > 0)) {
                for (DeviceElevatorAuthPO deviceElevatorAuthPO:deviceElevatorAuthPOS) {
                    String deviceAuth = deviceElevatorAuthPO.getDeviceAuth();
                    StringBuffer deviceAuthBuffer = new StringBuffer(deviceAuth);
                    String floorAuth = deviceElevatorAuthPO.getFloorAuth();
                    if (floorAuth != null) {
                        String[] floorAuthArr = floorAuth.split(",");

                        //记录旧的权限中权限码对应的楼层权限个数位置
                        int floorAuthPosition = 0;
                        for (int index = 0;index < deviceAuth.length();) {
                            int devicePosition = deviceAuth.indexOf(PlatformConstants.ELEVATOR_AUTHNUM, index);
                            if (devicePosition < 0) {
                                break;
                            }
                            //旧的不在新的中则去除
                            if (!elevatorPositionAtAuth.contains(devicePosition)) {
                                deviceAuthBuffer.setCharAt(devicePosition, PlatformConstants.ELEVATOR_NOAUTHNUM.charAt(0));
                                floorAuthArr[floorAuthPosition] = null;
                            } else if (elevatorPositionAtAuth.contains(devicePosition)) {
                                //28位的十六进制码
                                String oldFloorAuth = floorAuthArr[floorAuthPosition];
                                //以英文逗号拼接的非0自然数
                                String newNaturalFloor = naturalFloorList.get(elevatorPositionAtAuth.indexOf(devicePosition));
                                String resultFloorAuth = this.delNotIncludedFloor(oldFloorAuth, newNaturalFloor);
                                if (StringUtils.isEmpty(resultFloorAuth)) {
                                    deviceAuthBuffer.setCharAt(devicePosition, PlatformConstants.ELEVATOR_NOAUTHNUM.charAt(0));
                                    floorAuthArr[floorAuthPosition] = null;
                                } else {
                                    floorAuthArr[floorAuthPosition] = resultFloorAuth;
                                }
                            }
                            //在，则处理楼层权限
                            floorAuthPosition++;
                            index = ++devicePosition;
                        }
                        StringBuffer resultFloorAuthBuffer = new StringBuffer();
                        for (int index = 0;index < floorAuthArr.length;index++) {
                            if (StringUtils.isNotEmpty(floorAuthArr[index])) {
                                resultFloorAuthBuffer.append(floorAuthArr[index]).append(",");
                            }
                        }
                        if (resultFloorAuthBuffer.length() <= 0) {
                            //没有楼层权限，删除
                            iPropertyDeviceAuthElevatorAuthDao.deleteById(String.valueOf(deviceElevatorAuthPO.getId()));
                        } else {
                            //更新
                            deviceElevatorAuthPO.setFloorAuth(StringHandlerUtil.clearComma(resultFloorAuthBuffer).toString());
                            deviceElevatorAuthPO.setDeviceAuth(deviceAuthBuffer.toString());
                            deviceElevatorAuthPO.setUpdateTime(new Date());
                            iPropertyDeviceAuthElevatorAuthDao.update(deviceElevatorAuthPO);
                        }
                    }
                }
            }
            if ((entrancePositionAtAuth.size() > 0) &&
                    (deviceEntranceAuthPOS != null && deviceEntranceAuthPOS.size() > 0)) {
                for (DeviceEntranceAuthPO deviceEntranceAuthPO:deviceEntranceAuthPOS) {
                    String deviceAuth = deviceEntranceAuthPO.getDeviceAuth();
                    StringBuffer deviceAuthBuffer = new StringBuffer(deviceAuth);
                    for (int index = 0;index < deviceAuth.length();) {
                        int devicePosition = deviceAuth.indexOf(PlatformConstants.ENTRANCE_AUTHNUM, index);
                        if (devicePosition < 0) {
                            break;
                        }
                        if (!entrancePositionAtAuth.contains(devicePosition)) {
                            deviceAuthBuffer.setCharAt(devicePosition, PlatformConstants.ENTRANCE_NOAUTHNUM.charAt(0));
                        }
                        index = ++devicePosition;
                    }
                    //权限码中全为无权限则删除，反之更新
                    boolean hasAuthCode = false;
                    for (int index = 0;index < deviceAuthBuffer.length();index++) {
                        if (!StringHandlerUtil.compareStrWithOutEmpty(PlatformConstants.ENTRANCE_NOAUTHNUM,
                                StringHandlerUtil.copySubStr(deviceAuthBuffer.toString(), index, 1))){
                            hasAuthCode = true;
                            break;
                        }
                    }
                    if (hasAuthCode) {
                        deviceEntranceAuthPO.setDeviceAuth(deviceAuthBuffer.toString());
                        deviceEntranceAuthPO.setUpdateTime(new Date());
                        iPropertyDeviceAuthEntranceAuthDao.update(deviceEntranceAuthPO);
                    } else {
                        iPropertyDeviceAuthEntranceAuthDao.deleteById(String.valueOf(deviceEntranceAuthPO.getId()));
                    }
                }
            }
            if ((cloudIntercomPositionAtAuth.size() > 0) &&
                    (deviceCloudIntercomAuthPOS != null && deviceCloudIntercomAuthPOS.size() > 0)) {
                for (DeviceCloudIntercomAuthPO deviceCloudIntercomAuthPO:deviceCloudIntercomAuthPOS) {
                    String deviceAuth = deviceCloudIntercomAuthPO.getDeviceAuth();
                    StringBuffer deviceAuthBuffer = new StringBuffer(deviceAuth);
                    for (int index = 0;index < deviceAuth.length();) {
                        int devicePosition = deviceAuth.indexOf(PlatformConstants.CLOUD_INTERCOM_AUTHNUM, index);
                        if (devicePosition < 0) {
                            break;
                        }
                        if (!cloudIntercomPositionAtAuth.contains(devicePosition)) {
                            deviceAuthBuffer.setCharAt(devicePosition, PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM.charAt(0));
                        }
                        index = ++devicePosition;
                    }
                    //权限码中全为无权限则删除，反之更新
                    boolean hasAuthCode = false;
                    for (int index = 0;index < deviceAuthBuffer.length();index++) {
                        if (!StringHandlerUtil.compareStrWithOutEmpty(PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM,
                                StringHandlerUtil.copySubStr(deviceAuthBuffer.toString(), index, 1))){
                            hasAuthCode = true;
                            break;
                        }
                    }
                    if (hasAuthCode) {
                        deviceCloudIntercomAuthPO.setUpdateTime(new Date());
                        deviceCloudIntercomAuthPO.setDeviceAuth(deviceAuthBuffer.toString());
                        iPropertyDeviceAuthCloudIntercomAuthDao.update(deviceCloudIntercomAuthPO);
                    } else {
                        iPropertyDeviceAuthCloudIntercomAuthDao.deleteById(String.valueOf(deviceCloudIntercomAuthPO.getId()));
                    }
                }
            }
        }
    }

    /**
     * <desc>
     *      新旧楼层权限对比，若旧的某些不在新的中则去除
     * <desc/>
     * @param oldFloorAuth  旧的楼层权限(28位的十六进制码)
     * @param newNaturalFloor  新的楼层权限(以英文逗号拼接的非0自然数)
     * @return String 去除后的楼层权限(28位的十六进制码)
     * @author zhangs
     * @createDate 2018/03/01
     */
    private String delNotIncludedFloor(String oldFloorAuth, String newNaturalFloor) throws Exception {
        String result = null;
        if (StringUtils.isEmpty(oldFloorAuth)) {
            return result;
        }
        if (StringUtils.isEmpty(newNaturalFloor)) {
            return oldFloorAuth;
        }
        StringBuffer resultBuffer = new StringBuffer();
        List<String> newNaturalList = Arrays.asList(newNaturalFloor.split(","));
        String[] oldNaturalFloorArr = StringHandlerUtil.getNaturalFloorsByAuthCode(oldFloorAuth).split(",");
        for (int index = 0;index < oldNaturalFloorArr.length;index++) {
            if (newNaturalList.contains(oldNaturalFloorArr[index])) {
                resultBuffer.append(oldNaturalFloorArr[index]).append(",");
            }
        }
        if (resultBuffer.length() <= 0) {
            return result;
        }
        return StringHandlerUtil.getAuthCodeBynNturalFloors(StringHandlerUtil.clearComma(resultBuffer).toString());
    }

    /**
     * <desc>
     *      更新或清除用户设备权限
     * <desc/>
     *
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @param authUserId  授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 权限来源
     * @param param 条件
     * @author zhangs
     * @createDate 2018/02/26
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateOrDelUserDeviceAuthToDB(
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS,
            String authUserId,
            String userId,
            String projectId,
            Integer authSource,
            Map<String, Object> param) throws Exception {
        int elevatorCount = PlatformConstants.MAX_ELEVATOR_DEVICEID;
        int entranceCount = PlatformConstants.MAX_ENTRANCE_DEVICEID;
        int cloudCount = PlatformConstants.MAX_CLOUD_INTERCOM_DEVICEID;

        Map<String, Object> deviceMap = this.getMergeDeviceUnique(appUserGetDeviceAuthVOS);
        StringBuffer elevatorDevice;
        elevatorDevice = (StringBuffer) deviceMap.get("elevatorDevice");
        StringBuffer naturalFloorBuffer;
        naturalFloorBuffer = (StringBuffer) deviceMap.get("naturalFloorBuffer");
        StringBuffer entranceDevice;
        entranceDevice = (StringBuffer) deviceMap.get("entranceDevice");
        StringBuffer cloudDevice;
        cloudDevice = (StringBuffer) deviceMap.get("cloudDevice");

        if((elevatorDevice.length() > 0) && (naturalFloorBuffer.length() > 0)) {
            //更新用户电梯设备权限信息
            this.updateUserDeviceElevator(
                    authUserId, userId, projectId, elevatorDevice, naturalFloorBuffer, elevatorCount, authSource);
        } else {
            //清除住户在当前小区的电梯设备权限
            iPropertyDeviceAuthElevatorAuthDao.delByParam(param);
        }
        if(entranceDevice.length() > 0) {
            //更新用户门禁设备权限信息
            this.updateUserDeviceEntrance(
                    authUserId, userId, projectId, entranceDevice, entranceCount, authSource);
        } else {
            //清除住户在当前小区的门禁设备权限
            iPropertyDeviceAuthEntranceAuthDao.delByParam(param);
        }
        if(cloudDevice.length() > 0) {
            //更新用户云对讲设备权限信息
            this.updateUserDeviceCloud(
                    authUserId, userId, projectId, cloudDevice, cloudCount, authSource);
        } else {
            //清除住户在当前小区的云对讲设备权限
            iPropertyDeviceAuthCloudIntercomAuthDao.delByParam(param);
        }
    }

    /**
     * <desc>
     *      设备变更更新用户设备权限
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @param authSource  权限来源
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateUserDeviceAuth (
            String authUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS,
            Integer authSource) throws Exception{
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) || appUserGetDeviceAuthVOS.size() == 0) {
            return ;
        }

        Map<String, Object> deviceMap = this.getMergeDeviceUnique(appUserGetDeviceAuthVOS);
        StringBuffer elevatorDevice;
        elevatorDevice = (StringBuffer) deviceMap.get("elevatorDevice");
        StringBuffer naturalFloorBuffer;
        naturalFloorBuffer = (StringBuffer) deviceMap.get("naturalFloorBuffer");
        StringBuffer entranceDevice;
        entranceDevice = (StringBuffer) deviceMap.get("entranceDevice");
        StringBuffer cloudDevice;
        cloudDevice = (StringBuffer) deviceMap.get("cloudDevice");

        int elevatorCount = PlatformConstants.MAX_ELEVATOR_DEVICEID;
        int entranceCount = PlatformConstants.MAX_ENTRANCE_DEVICEID;
        int cloudCount = PlatformConstants.MAX_CLOUD_INTERCOM_DEVICEID;

        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        param.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            param.put("authUserId", authUserId);
        }

        if((elevatorDevice.length() > 0) && (naturalFloorBuffer.length() > 0)) {
            //更新用户电梯设备权限信息
            this.updateUserDeviceElevator(
                    authUserId, userId, projectId, elevatorDevice, naturalFloorBuffer, elevatorCount, authSource);
        } else {
            //清除住户在当前小区的电梯设备权限
            iPropertyDeviceAuthElevatorAuthDao.delByParam(param);
        }
        if(entranceDevice.length() > 0) {
            //更新用户门禁设备权限信息
            this.updateUserDeviceEntrance(
                    authUserId, userId, projectId, entranceDevice, entranceCount, authSource);
        } else {
            //清除住户在当前小区的门禁设备权限
            iPropertyDeviceAuthEntranceAuthDao.delByParam(param);
        }
        if(cloudDevice.length() > 0) {
            //更新用户云对讲设备权限信息
            this.updateUserDeviceCloud(
                    authUserId, userId, projectId, cloudDevice, cloudCount, authSource);
        } else {
            //清除住户在当前小区的云对讲设备权限
            iPropertyDeviceAuthCloudIntercomAuthDao.delByParam(param);
        }
    }

    /**
     * <desc>
     *      合并设备唯一码(含楼层)信息
     * <desc/>
     *
     * @param  appUserGetDeviceAuthVOS  App用户Id
     * @return map 合并后的设备唯一码(含楼层)信息
     * @author zhangs
     * @createDate 2017/09/25
     */
    private Map<String, Object> getMergeDeviceUnique(List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS) {
        StringBuffer elevatorDevice = new StringBuffer();
        StringBuffer naturalFloorBuffer = new StringBuffer();
        //待排序设备唯一码和对应楼层信息集合(eg: map.put("0000030410008", "1000000000000000000000000000");)
        Map<String, String> param = new HashMap<>();
        StringBuffer entranceDevice = new StringBuffer();
        StringBuffer cloudDevice = new StringBuffer();
        for(AppUserGetDeviceAuthVO appUserGetDeviceAuthVO:appUserGetDeviceAuthVOS) {
            String deviceType = appUserGetDeviceAuthVO.getDeviceType();
            String deviceUnique = appUserGetDeviceAuthVO.getDeviceUnique();
            if (!StringUtils.isNumeric(deviceType)) {
                continue;
            }
            switch(Integer.parseInt(deviceType)) {
                case DEVICEAUTH_DEVICETYPE_ELEVATOR:
                    String naturalFloor = appUserGetDeviceAuthVO.getNaturalFloor();
                    if ((StringUtils.isNotBlank(deviceUnique)) && (StringUtils.isNotEmpty(naturalFloor))) {
                        elevatorDevice.append(deviceUnique).append(",");
                        if(param.get(deviceUnique) != null ){
                            String append = StringHandlerUtil.getNaturalFloorsByAuthCode(param.get(deviceUnique).toString());
                            Set<String> natural = new HashSet<>();
                            String[] nFloor = StringHandlerUtil.splitString(naturalFloor);
                            String[] appends = StringHandlerUtil.splitString(append);
                            for(String f : nFloor){
                                natural.add(f);
                            }
                            for(String a : appends){
                                natural.add(a);
                            }
                            naturalFloor = StringUtils.join(natural,",");
                        }
                        param.put(deviceUnique, StringHandlerUtil.getAuthCodeBynNturalFloors(naturalFloor));
                    }
//                    naturalFloorBuffer.append(StringHandlerUtil.getAuthCodeBynNturalFloors(naturalFloor)).append(",");
                    break;
                case DEVICEAUTH_DEVICETYPE_ENTRANCE:
                    entranceDevice.append(deviceUnique).append(",");
                    break;
                case DEVICEAUTH_DEVICETYPE_CLOUDINTERCOM:
                    cloudDevice.append(deviceUnique).append(",");
                    break;
                default:
                    LOG.info(String.format("【物业系统_更新用户设备权限出错_updateUserDeviceAuth()】info:{%s}", appUserGetDeviceAuthVO));
                    break;
            }
        }

        //排序后的设备唯一码和对应楼层信息集合
        param = this.mapSortByKey(param);
        Iterator iterator = param.values().iterator();
        while (iterator.hasNext()) {
            naturalFloorBuffer.append(iterator.next()).append(",");
        }
        Map<String, Object> deviceMap = new HashMap<>();
        deviceMap.put("elevatorDevice", elevatorDevice);
        deviceMap.put("naturalFloorBuffer", StringHandlerUtil.clearComma(naturalFloorBuffer));
        deviceMap.put("entranceDevice", entranceDevice);
        deviceMap.put("cloudDevice", cloudDevice);
        return deviceMap;
    }

    /**
     * <desc>
     *      通过Map中的Key进行升序排列(降楼层信息按照设备唯一码进行升序排列)
     * <desc/>
     *
     * @param param 待排序设备唯一码和对应楼层信息集合(eg: map.put("0000030410008", "1000000000000000000000000000");)
     * @return Map<String, String> 排序后的Map集合
     * @author zhangs
     * @createDate 2017/10/10
     */
    private Map<String, String> mapSortByKey(Map<String, String> param) {
        Map<String, String> map = new TreeMap<String, String>(
                new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        //升序排列
                        return o1.compareTo(o2);
                        //降序排列
//                    return o2.compareTo(o1);
                    }
                }
        );
        map.putAll(param);
        return map;
    }

    /**
     * <desc>
     *      更新用户电梯设备权限信息
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param elevatorDevice 电梯设备唯一码字符串
     * @param naturalFloorBuffer 楼层字符串
     * @param elevatorCount 电梯设备数量
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    private Integer updateUserDeviceElevator(
            String authUserId,
            String userId,
            String projectId,
            StringBuffer elevatorDevice,
            StringBuffer naturalFloorBuffer,
            int elevatorCount,
            Integer authSource) throws Exception{
        Integer result = 0;
        if((elevatorDevice == null || elevatorDevice.length() == 0) ||
                (naturalFloorBuffer == null || naturalFloorBuffer.length() == 0)) {
            return result;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            params.put("authUserId", authUserId);
        }
        //获取用户旧的设备权限信息
        List<DeviceElevatorAuthPO> deviceElevatorAuthPOS = iPropertyDeviceAuthElevatorAuthDao.getUserDeviceElevatorAuth(params);

        DeviceElevatorAuthPO deviceElevatorAuthPO;//getDeviceAuthString
//        String deviceAuth = this.getDeviceAuthStringForElevator(userId,StringHandlerUtil.clearComma(elevatorDevice).toString(),
//                PlatformConstants.ELEVATOR_AUTHNUM, PlatformConstants.ELEVATOR_NOAUTHNUM, elevatorCount);
        String deviceAuth = this.getDeviceAuthString(StringHandlerUtil.clearComma(elevatorDevice).toString(),
                PlatformConstants.ELEVATOR_AUTHNUM, PlatformConstants.ELEVATOR_NOAUTHNUM, elevatorCount);

        //更新或保存用户设备权限.更新以避免过多的删除
        if(deviceElevatorAuthPOS != null && deviceElevatorAuthPOS.size() > 0) {
            DeviceElevatorAuthPO oldDeviceElevatorAuthPO = deviceElevatorAuthPOS.get(0);
            Integer delResult = iPropertyDeviceAuthElevatorAuthDao.deleteById(String.valueOf(oldDeviceElevatorAuthPO.getId()));
            if (delResult > 0) {
                deviceElevatorAuthPO = new DeviceElevatorAuthPO(userId, projectId, oldDeviceElevatorAuthPO.getUserType(),
                        oldDeviceElevatorAuthPO.getValiTime(), deviceAuth, StringHandlerUtil.clearComma(naturalFloorBuffer).toString(),
                        oldDeviceElevatorAuthPO.getCommonChoiceFloor(), oldDeviceElevatorAuthPO.getLiveChoiceFloor(),
                        oldDeviceElevatorAuthPO.getDynamicPwd(), oldDeviceElevatorAuthPO.getStaticPwd(),
                        authSource, authUserId);
                deviceElevatorAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
                deviceElevatorAuthPO.setCreateTime(oldDeviceElevatorAuthPO.getCreateTime());
                deviceElevatorAuthPO.setUpdateTime(new Date());

                result = iPropertyDeviceAuthElevatorAuthDao.save(SqlUtil.durableData(deviceElevatorAuthPO, PlatformConstants.TABLE_SAVE));
            }
        } else {
            deviceElevatorAuthPO = new DeviceElevatorAuthPO(userId, projectId, null,
                    DateUtil.fomatLongDate("2099-12-31 23:59:59"), deviceAuth, StringHandlerUtil.clearComma(naturalFloorBuffer).toString(),
                    null, null,null, null,
                    authSource, authUserId);
            deviceElevatorAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
            Date date = new Date();
            deviceElevatorAuthPO.setCreateTime(date);
            deviceElevatorAuthPO.setUpdateTime(date);
            result = iPropertyDeviceAuthElevatorAuthDao.save(SqlUtil.durableData(deviceElevatorAuthPO, PlatformConstants.TABLE_SAVE));
        }
        return result;
    }

    /**
     * <desc>
     *      更新用户门禁设备权限信息
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param entranceDevice 门禁设备唯一码字符串
     * @param entranceCount 门禁设备数量
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    private Integer updateUserDeviceEntrance(
            String authUserId,
            String userId,
            String projectId,
            StringBuffer entranceDevice,
            int entranceCount,
            Integer authSource) throws Exception{
        Integer result = 0;
        if(entranceDevice.length() == 0) {
            return result;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            params.put("authUserId", authUserId);
        }
        //获取用户旧的设备权限信息
        List<DeviceEntranceAuthPO> deviceEntranceAuthPOS = iPropertyDeviceAuthEntranceAuthDao.getUserDeviceEntranceAuth(params);

        DeviceEntranceAuthPO deviceEntranceAuthPO;
        String deviceAuth = this.getDeviceAuthString(StringHandlerUtil.clearComma(entranceDevice).toString(),
                PlatformConstants.ENTRANCE_AUTHNUM, PlatformConstants.ENTRANCE_NOAUTHNUM, entranceCount);

        //更新或保存用户设备权限.更新以避免过多的删除
        if(deviceEntranceAuthPOS.size() != 0) {
            DeviceEntranceAuthPO oldDeviceEntranceAuthPO = deviceEntranceAuthPOS.get(0);
            Integer delResult = iPropertyDeviceAuthEntranceAuthDao.deleteById(String.valueOf(oldDeviceEntranceAuthPO.getId()));
            if (delResult > 0) {
                deviceEntranceAuthPO = new DeviceEntranceAuthPO(userId, projectId, oldDeviceEntranceAuthPO.getUserType(),
                        oldDeviceEntranceAuthPO.getValiTime(), deviceAuth, oldDeviceEntranceAuthPO.getDynamicPwd(),
                        oldDeviceEntranceAuthPO.getStaticPwd(), authSource,authUserId);
                deviceEntranceAuthPO.setCreateTime(oldDeviceEntranceAuthPO.getCreateTime());
                deviceEntranceAuthPO.setUpdateTime(new Date());
                deviceEntranceAuthPO.setDeviceAuth(deviceAuth);
                deviceEntranceAuthPO.setStatus(DataStatusEnum.NORMAL.getType());

                result = iPropertyDeviceAuthEntranceAuthDao.save(SqlUtil.durableData(deviceEntranceAuthPO, PlatformConstants.TABLE_SAVE));
            }
        } else {
            deviceEntranceAuthPO = new DeviceEntranceAuthPO(userId, projectId, null,
                    DateUtil.fomatLongDate("2099-12-31 23:59:59"), deviceAuth, null, null,
                    authSource, authUserId);
            deviceEntranceAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
            Date date = new Date();
            deviceEntranceAuthPO.setCreateTime(date);
            deviceEntranceAuthPO.setUpdateTime(date);
            result = iPropertyDeviceAuthEntranceAuthDao.save(SqlUtil.durableData(deviceEntranceAuthPO, PlatformConstants.TABLE_SAVE));
        }
        return result;
    }

    /**
     * <desc>
     *      更新用户云对讲设备权限信息
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param cloudDevice 云对讲设备唯一码字符串
     * @param cloudCount 云对讲设备数量
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    private Integer updateUserDeviceCloud(
            String authUserId,
            String userId,
            String projectId,
            StringBuffer cloudDevice,
            int cloudCount,
            Integer authSource) throws Exception {
        Integer result = 0;
        if(cloudDevice.length() == 0) {
            return result;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            params.put("authUserId", authUserId);
        }
        //获取用户旧的设备权限信息
        List<DeviceCloudIntercomAuthPO> deviceCloudIntercomAuthPOS = iPropertyDeviceAuthCloudIntercomAuthDao.getUserDeviceCloudIntercomAuth(params);

        DeviceCloudIntercomAuthPO deviceCloudIntercomAuthPO;
        String deviceAuth = this.getDeviceAuthString(StringHandlerUtil.clearComma(cloudDevice).toString(),
                PlatformConstants.CLOUD_INTERCOM_AUTHNUM, PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM, cloudCount);

        //更新或保存用户设备权限.更新以避免过多的删除
        if (deviceCloudIntercomAuthPOS.size() != 0) {
            DeviceCloudIntercomAuthPO oldDeviceCloudIntercomAuthPO = deviceCloudIntercomAuthPOS.get(0);
            iPropertyDeviceAuthCloudIntercomAuthDao.deleteById(String.valueOf(oldDeviceCloudIntercomAuthPO.getId()));
            deviceCloudIntercomAuthPO = new DeviceCloudIntercomAuthPO(userId, projectId, oldDeviceCloudIntercomAuthPO.getUserType(),
                    oldDeviceCloudIntercomAuthPO.getValiTime(), deviceAuth, oldDeviceCloudIntercomAuthPO.getDynamicPwd(),
                    oldDeviceCloudIntercomAuthPO.getStaticPwd(), authSource, authUserId);
            deviceCloudIntercomAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
            deviceCloudIntercomAuthPO.setCreateTime(oldDeviceCloudIntercomAuthPO.getCreateTime());
            deviceCloudIntercomAuthPO.setUpdateTime(new Date());
            result = iPropertyDeviceAuthCloudIntercomAuthDao.save(SqlUtil.durableData(deviceCloudIntercomAuthPO, PlatformConstants.TABLE_SAVE));
        } else {
            deviceCloudIntercomAuthPO = new DeviceCloudIntercomAuthPO(userId, projectId, null,
                    DateUtil.fomatLongDate("2099-12-31 23:59:59"), deviceAuth, null, null,
                    authSource, authUserId);
            deviceCloudIntercomAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
            Date date = new Date();
            deviceCloudIntercomAuthPO.setCreateTime(date);
            deviceCloudIntercomAuthPO.setUpdateTime(date);
            result = iPropertyDeviceAuthCloudIntercomAuthDao.save(SqlUtil.durableData(deviceCloudIntercomAuthPO, PlatformConstants.TABLE_SAVE));
        }
        return result;
    }

    /**
     * <desc>
     *      通知App对应后台模块做相应更新
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param jPushMessage  极光推送信息
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    private void noticeOtherServiceRedis(String userId, String projectId, String jPushMessage) throws Exception{
        //住户设备权限更新时通知后台移动App模块
        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        if (StringUtils.isNotEmpty(jPushMessage)) {
            param.put("data", jPushMessage);
        }
        messageSender.send(RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_QUEUE,
                JSON.toJSONString(param), RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
                RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_KEY);
    }

    /**
     * <desc>
     *      更新redis中用户设备权限信息
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param jPushMessage  极光推送信息
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    public void updateUserDeviceAuthAtRedis(String userId, String projectId,boolean needNotifySmartCard, String jPushMessage) throws Exception{
        //LOG.info("【物业系统_住户管理_用户设备权限】开始更新redis中的物业住户设备权限");

        //更新缓存redis中住户在本项目下的设备权限
        if(StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(projectId)) {
            //与旺龙一卡通对接-收集云端住户设备权限变动数据
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOSForSmartCard = new ArrayList<>();
            appUserGetDeviceAuthVOSForSmartCard.addAll(this.getDeviceAuth(userId, projectId,
                    String.valueOf(PropertyEquipTypeEnum.ELEVATOR.getType())));

            //与旺龙一卡通对接-收集云端住户设备权限变动数据
            if (needNotifySmartCard){
                appUserGetDeviceAuthVOSForSmartCard.addAll(this.getDeviceAuth(userId, projectId,
                        String.valueOf(PropertyEquipTypeEnum.ENTRANCE.getType())));
                List<SmartCardSyncDataTmpAuthDTO> smartCardSyncDataTmpAuthDTOS = new ArrayList<>();
                SmartCardSyncDataTmpAuthDTO smartCardSyncDataTmpAuthDTO = new SmartCardSyncDataTmpAuthDTO();
                smartCardSyncDataTmpAuthDTO.setUserId(userId);
                smartCardSyncDataTmpAuthDTO.setAppUserGetDeviceAuthVOS(appUserGetDeviceAuthVOSForSmartCard);
                smartCardSyncDataTmpAuthDTOS.add(smartCardSyncDataTmpAuthDTO);
                this.prepareUserAuthInfoForSyncToSmartCard(projectId, smartCardSyncDataTmpAuthDTOS, SmartCardSyncDataOperTypeEnum.UPDATE);

            }
        }
        //权限变更通知其他模块更新相应缓存redis
        this.noticeOtherServiceRedis(userId, projectId, jPushMessage);
    }

    /**
     * <desc>
     *      用户设备权限-获取授权设备信息云电梯用(有权限的设备自然数字符串，如00011011...、78877..77等)
     * <desc/>
     *
     * @param deviceUniques 设备唯一码,已英文,拼接
     * @param authNum 有权限设备自然数字符串标识
     * @param noAuthNum 无权限设备自然数字符串标识
     * @param deviceCount 设备总数
     * @return String
     * @author Qiang.S
     * @createDate 2019/05/22
     */
    private String getDeviceAuthStringForElevator(
            String userId,
            String deviceUniques,
            String authNum,
            String noAuthNum,
            int deviceCount) {
        if(StringUtils.isBlank(deviceUniques) || StringUtils.isBlank(authNum) || StringUtils.isBlank(noAuthNum)) {
            return null;
        }
        //用户,正背门
        StringBuffer deviceAuthBuffer = new StringBuffer(deviceCount);
        for(int i = 0;i < deviceCount;i++) {
            deviceAuthBuffer.append(noAuthNum);
        }
        String[] deviceTemp = deviceUniques.split(",");

        //查询设备地址,之后用户房间地址和设备地址进行权限验证
        List<String> deviceUniqueList = new ArrayList<>();
        List<CloudElevatorLiftDoorTypeVO> listDevice = iPropertyDeviceAuthElevatorAuthDao.getDeviceLiftDoorTypeInfo(deviceTemp);
        List<CloudElevatorLiftDoorTypeVO> listUser = iPropertyDeviceAuthElevatorAuthDao.getUserLiftDoorTypeInfo(userId);
        for (CloudElevatorLiftDoorTypeVO voDevice : listDevice) {
            for (CloudElevatorLiftDoorTypeVO voUser : listUser) {
                if (voDevice.getUnitId().equals(voUser.getUnitId()) && voDevice.getLiftDoorType().contains(voUser.getLiftDoorType())) {
                    deviceUniqueList.add(voDevice.getDeviceUnique());
                    continue;
                }
            }
        }

        for (String aDeviceTemp : deviceUniqueList) {
            if (StringUtils.isNotBlank(aDeviceTemp)) {
                //获取设备编号，设备编号即是在授权设备信息自然数字符串中的位置,设备编号0002即是第二位
                if (!StringUtils.isNumeric(StringHandlerUtil.copySubStr(aDeviceTemp, 9, 4))) {
                    continue;
                }
                int positionNum = Integer.parseInt(StringHandlerUtil.copySubStr(aDeviceTemp, 9, 4));
                deviceAuthBuffer.setCharAt(positionNum - 1, authNum.charAt(0));
            }
        }
        return deviceAuthBuffer.toString();
    }

    /**
     * <desc>
     *      用户设备权限-获取授权设备信息(有权限的设备自然数字符串，如00011011...、78877..77等)
     * <desc/>
     *
     * @param deviceUniques 设备唯一码,已英文,拼接
     * @param authNum 有权限设备自然数字符串标识
     * @param noAuthNum 无权限设备自然数字符串标识
     * @param deviceCount 设备总数
     * @return String
     * @author zhangs
     * @createDate 2017/10/10
     */
    private String getDeviceAuthString(
            String deviceUniques,
            String authNum,
            String noAuthNum,
            int deviceCount) {
        if(StringUtils.isBlank(deviceUniques) || StringUtils.isBlank(authNum) || StringUtils.isBlank(noAuthNum)) {
            return null;
        }
        StringBuffer deviceAuthBuffer = new StringBuffer(deviceCount);
        for(int i = 0;i < deviceCount;i++) {
            deviceAuthBuffer.append(noAuthNum);
        }
        String[] deviceTemp = deviceUniques.split(",");
        for (String aDeviceTemp : deviceTemp) {
            if (StringUtils.isNotBlank(aDeviceTemp)) {
                //获取设备编号，设备编号即是在授权设备信息自然数字符串中的位置,设备编号0002即是第二位
                if (!StringUtils.isNumeric(StringHandlerUtil.copySubStr(aDeviceTemp, 9, 4))) {
                    continue;
                }
                int positionNum = Integer.parseInt(StringHandlerUtil.copySubStr(aDeviceTemp, 9, 4));
                deviceAuthBuffer.setCharAt(positionNum - 1, authNum.charAt(0));
            }
        }
        return deviceAuthBuffer.toString();
    }

    /**
     * <desc>
     *      获取用户在当前项目中的特定设备类型的设备权限(数据库查找)
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param deviceType 设备类型
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    private List<AppUserGetDeviceAuthVO> getDeviceAuth(String userId, String projectId, String deviceType) {
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        //用于暂存用户设备权限
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOList;
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) || StringUtils.isBlank(deviceType)) {
            return appUserGetDeviceAuthVOS;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        params.put("projectId", projectId);
        if (!StringUtils.isNumeric(deviceType)) {
            return appUserGetDeviceAuthVOS;
        }
        switch(Integer.parseInt(deviceType)) {
            case DEVICEAUTH_DEVICETYPE_ELEVATOR:
                appUserGetDeviceAuthVOList = new ArrayList<>();
                //获取电梯设备权限
                List<DeviceElevatorAuthPO> deviceElevatorAuthPOS = iPropertyDeviceAuthElevatorAuthDao.getUserDeviceElevatorAuth(params);
                if(deviceElevatorAuthPOS.size() != 0) {
                    for(DeviceElevatorAuthPO deviceElevatorAuthPO:deviceElevatorAuthPOS) {
                        //设备权限来源标识(1:一卡通 2:物业后台,5临时权限 6分组权限)
                        Integer authSource = deviceElevatorAuthPO.getAuthSource();
                        //二进制的设备信息
                        String auth = deviceElevatorAuthPO.getDeviceAuth();
                        if (StringUtils.isNotBlank(auth)) {
                            StringBuffer deviceAuth = new StringBuffer(auth);
                            //十六进制的楼层信息数组
                            String floorAuth = deviceElevatorAuthPO.getFloorAuth();
                            //将设备权限信息进行进制转换后暂存
//                        appUserGetDeviceAuthVOList.addAll(this.getConvertElevatorDeviceAuth(authSource, deviceAuth, floorAuth, projectId));
                            appUserGetDeviceAuthVOList.addAll(this.getConvertElevatorAuth(authSource, deviceAuth, floorAuth, projectId));
                        }
                    }
                    //合并相同类型设备权限
                    appUserGetDeviceAuthVOS.addAll(this.mergeSameTypeDeviceAuth(appUserGetDeviceAuthVOList));
                }
                break;
            case DEVICEAUTH_DEVICETYPE_ENTRANCE:
                appUserGetDeviceAuthVOList = new ArrayList<>();
                //获取门禁设备权限(由地址得到的有权限设备的Set)
                List<DeviceEntranceAuthPO> deviceEntranceAuthPOS = iPropertyDeviceAuthEntranceAuthDao.getUserDeviceEntranceAuth(params);
                if(deviceEntranceAuthPOS.size() != 0) {
                    for(DeviceEntranceAuthPO deviceEntranceAuthPO:deviceEntranceAuthPOS) {
                        //设备权限来源标识(1:一卡通 2:物业后台,5临时权限 6分组权限)
                        Integer authSource = deviceEntranceAuthPO.getAuthSource();
                        //十进制的设备信息
                        String auth = deviceEntranceAuthPO.getDeviceAuth();
                        if (StringUtils.isNotBlank(auth)) {
                            StringBuffer deviceAuth = new StringBuffer(auth);
                            //将设备权限信息进行进制转换后暂存
                            appUserGetDeviceAuthVOList.addAll(this.getConvertEntranceDeviceAuth(authSource, deviceAuth, projectId));
                        }
                    }
                    //合并相同类型设备权限
                    appUserGetDeviceAuthVOS.addAll(this.mergeSameTypeDeviceAuth(appUserGetDeviceAuthVOList));
                }
                break;
            case DEVICEAUTH_DEVICETYPE_CLOUDINTERCOM:
                appUserGetDeviceAuthVOList = new ArrayList<>();
                //获取云对讲设备权限
                List<DeviceCloudIntercomAuthPO> deviceCloudIntercomAuthPOS = iPropertyDeviceAuthCloudIntercomAuthDao.getUserDeviceCloudIntercomAuth(params);
                if(deviceCloudIntercomAuthPOS.size() != 0) {
                    for(DeviceCloudIntercomAuthPO deviceCloudIntercomAuthPO:deviceCloudIntercomAuthPOS) {
                        //设备权限来源标识(1:一卡通 2:物业后台)
                        Integer authSource = deviceCloudIntercomAuthPO.getAuthSource();
                        //十进制的设备信息
                        String deviceAuth = deviceCloudIntercomAuthPO.getDeviceAuth();
                        //将设备权限信息进行进制转换后暂存
                        appUserGetDeviceAuthVOList.addAll(this.getConvertCloudIntercomDeviceAuth(authSource, deviceAuth, projectId));
                    }
                    //合并相同类型设备权限
                    appUserGetDeviceAuthVOS.addAll(this.mergeSameTypeDeviceAuth(appUserGetDeviceAuthVOList));
                }
                break;
        }
        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      获得转换后的电梯设备权限
     * <desc/>
     *
     * @param authSource 设备权限来源标识(1:一卡通 2:物业后台)
     * @param deviceAuth 授权设备信息
     * @param floorAuth 授权楼层信息
     * @param projectId 项目Id
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    private List<AppUserGetDeviceAuthVO> getConvertElevatorDeviceAuth(
            Integer authSource,
            StringBuffer deviceAuth,
            String floorAuth,
            String projectId) {
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        if((deviceAuth == null) || StringUtils.isBlank(floorAuth)) {
            return appUserGetDeviceAuthVOS;
        }

        //authSource:设备权限来源标识(1:一卡通 2:物业后台)
        //isChecked:能否被选中(0设备授权-已选中且不可更改 1设备授权-已选中且可以更改  2设备授权-未选中)
        Integer isChecked ;
        if(Objects.equals(authSource, DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType())
                || Objects.equals(authSource, DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_YSE;
        } else {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_NO;
        }
        String deviceType = String.valueOf(PropertyEquipTypeEnum.ELEVATOR.getType());
        //十六进制的楼层信息数组
        String[] floorAuths = floorAuth.split(",");
        //设备位置角标
        int devIndex = 0;
        //楼层数据角标
        int floorsOfOneDevIndex = 0;
        //获取设备二进制数据中有权限码的位置，即设备编号，再组装成设备唯一码
        while(devIndex < deviceAuth.length() && deviceAuth.indexOf(PlatformConstants.ELEVATOR_AUTHNUM, devIndex) > -1) {
            AppUserGetDeviceAuthVO appUserGetDeviceAuthVO = new AppUserGetDeviceAuthVO();
            devIndex = deviceAuth.indexOf(PlatformConstants.ELEVATOR_AUTHNUM, devIndex) + 1;
            StringBuffer deviceUnique = new StringBuffer(projectId).
                    append(PropertyEquipTypeEnum.ELEVATOR.getType()).append(String.format("%04d", devIndex));
            appUserGetDeviceAuthVO.setDeviceUnique(deviceUnique.toString());
            //根据十六进制的楼层信息数据获取naturalFloor和logicalFloor
            String naturalHexFloorsOfOneDev = floorAuths[floorsOfOneDevIndex];
            if(StringUtils.isNotBlank(naturalHexFloorsOfOneDev)) {
                //获取naturalFloor
                String naturalCommaFloors = StringHandlerUtil.getNaturalFloorsByAuthCode(naturalHexFloorsOfOneDev);
                if (StringUtils.isBlank(naturalCommaFloors)){  //无楼层权限
                    floorsOfOneDevIndex++;
                    continue;
                }
                appUserGetDeviceAuthVO.setNaturalFloor(naturalCommaFloors);
                List<DeviceElevatorFloorConfigPO> deviceElevatorFloorConfigPOS =
                        iPropertyEquipService.getByNaturalFloors(deviceUnique.toString(),naturalCommaFloors);
                if (deviceElevatorFloorConfigPOS.isEmpty()) {
                    floorsOfOneDevIndex++;
                    continue;
                }

                //设备授权前端页面展示用的楼层名称
                String showfloors = this.getFloorByPOList(deviceElevatorFloorConfigPOS);
                appUserGetDeviceAuthVO.setIsChecked(isChecked);
                appUserGetDeviceAuthVO.setDeviceType(deviceType);
                //非地址映射的权限楼层(floorNum)存于tempFloor字段中用于标记由地址获取的电梯设备权限中哪些楼层可编辑
                if (appUserGetDeviceAuthVO.getIsChecked() == PlatformConstants.DEVICEAUTH_ISCHECKED_YSE) {
                    appUserGetDeviceAuthVO.setTempFloor(showfloors);
                } else {
                    appUserGetDeviceAuthVO.setLogicalFloor(showfloors);
                }
            }
            /*//非地址映射的权限楼层(logicalFloor)存于tempFloor字段中用于标记由地址获取的电梯设备权限中哪些楼层可编辑
            if (appUserGetDeviceAuthVO.getIsChecked() == PlatformConstants.DEVICEAUTH_ISCHECKED_YSE) {
                appUserGetDeviceAuthVO.setTempFloor(appUserGetDeviceAuthVO.getLogicalFloor());
            }*/
            appUserGetDeviceAuthVOS.add(appUserGetDeviceAuthVO);
            floorsOfOneDevIndex++;
        }

        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      获得转换后的电梯设备权限
     * <desc/>
     *
     * @param authSource 设备权限来源标识(1:一卡通 2:物业后台)
     * @param deviceAuth 授权设备信息
     * @param floorAuth 授权楼层信息
     * @param projectId 项目Id
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    private List<AppUserGetDeviceAuthVO> getConvertElevatorAuth(
            Integer authSource,
            StringBuffer deviceAuth,
            String floorAuth,
            String projectId) {
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        if((deviceAuth == null) || StringUtils.isBlank(floorAuth)) {
            return appUserGetDeviceAuthVOS;
        }

        //authSource:设备权限来源标识(1:一卡通 2:物业后台)
        //isChecked:能否被选中(0设备授权-已选中且不可更改 1设备授权-已选中且可以更改  2设备授权-未选中)
        Integer isChecked ;
        if(Objects.equals(authSource, DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType())
                || Objects.equals(authSource, DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_YSE;
        } else {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_NO;
        }
        String deviceType = String.valueOf(PropertyEquipTypeEnum.ELEVATOR.getType());
        //十六进制的楼层信息数组
        String[] floorAuths = floorAuth.split(",");
        //设备位置角标
        int devIndex = 0;
        //楼层数据角标
        int floorsOfOneDevIndex = 0;
        //获取设备二进制数据中有权限码的位置，即设备编号，再组装成设备唯一码
        //Map(List<deviceUnique>, naturalCommaFloors);naturalCommaFloors以英文逗号拼接
        Map<String, String> elevatorAuthMap = new HashMap<>();
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthTemps = new ArrayList<>();
        while (devIndex < deviceAuth.length() && deviceAuth.indexOf(PlatformConstants.ELEVATOR_AUTHNUM, devIndex) > -1) {
            AppUserGetDeviceAuthVO appUserGetDeviceAuthVO = new AppUserGetDeviceAuthVO();
            devIndex = deviceAuth.indexOf(PlatformConstants.ELEVATOR_AUTHNUM, devIndex) + 1;
            StringBuffer deviceUnique = new StringBuffer(projectId).
                    append(PropertyEquipTypeEnum.ELEVATOR.getType()).append(String.format("%04d", devIndex));
            appUserGetDeviceAuthVO.setDeviceUnique(deviceUnique.toString());
            String naturalHexFloorsOfOneDev = floorAuths[floorsOfOneDevIndex];
            if(StringUtils.isNotBlank(naturalHexFloorsOfOneDev)) {
                String naturalCommaFloors = StringHandlerUtil.getNaturalFloorsByAuthCode(naturalHexFloorsOfOneDev);
                if (StringUtils.isBlank(naturalCommaFloors)){  //无楼层权限
                    floorsOfOneDevIndex++;
                    continue;
                }
                //将住户设备权限信息临时存储，一次性查出住户所有电梯设备对应的楼层信息然后再做便利处理
                appUserGetDeviceAuthVO.setNaturalFloor(naturalCommaFloors);
                elevatorAuthMap.put(deviceUnique.toString(), naturalCommaFloors);
                appUserGetDeviceAuthTemps.add(appUserGetDeviceAuthVO);
                floorsOfOneDevIndex++;
            }
        }
        List<PropertyElevatorFloorGetVO> propertyElevatorFloorGetVOS = new ArrayList<>();
        if (elevatorAuthMap != null && elevatorAuthMap.size() > 0) {
            propertyElevatorFloorGetVOS = iPropertyEquipService.getAllFloorByElevator(elevatorAuthMap);
        }

        //电梯设备与其展示楼层Map集合。Map(deviceUnique,showFloors);
        Map<String, String> deviceElevatorFloorConfigPOMap = new HashMap<>();
        if (propertyElevatorFloorGetVOS != null && propertyElevatorFloorGetVOS.size() > 0) {
            for (PropertyElevatorFloorGetVO propertyElevatorFloorGetVO:propertyElevatorFloorGetVOS) {
                deviceElevatorFloorConfigPOMap.put(propertyElevatorFloorGetVO.getDeviceUnique(),propertyElevatorFloorGetVO.getShowFloors());
            }

            for (AppUserGetDeviceAuthVO appUserGetDeviceAuthVO:appUserGetDeviceAuthTemps) {
                String deviceUnique = appUserGetDeviceAuthVO.getDeviceUnique();
                //设备授权前端页面展示用的楼层名称
                String showfloors = deviceElevatorFloorConfigPOMap.get(deviceUnique);
                appUserGetDeviceAuthVO.setIsChecked(isChecked);
                appUserGetDeviceAuthVO.setDeviceType(deviceType);
                //非地址映射的权限楼层(floorNum)存于tempFloor字段中用于标记由地址获取的电梯设备权限中哪些楼层可编辑
                if (appUserGetDeviceAuthVO.getIsChecked() == PlatformConstants.DEVICEAUTH_ISCHECKED_YSE) {
                    appUserGetDeviceAuthVO.setTempFloor(showfloors);
                } else {
                    appUserGetDeviceAuthVO.setLogicalFloor(showfloors);
                }
                appUserGetDeviceAuthVOS.add(appUserGetDeviceAuthVO);
            }
        }
        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      组装拼接合成logicalFloor
     * <desc/>
     *
     * @param deviceElevatorFloorConfigPOS 电梯楼层映射信息
     * @return String 设备授权展示用的楼层数(指添加电梯设备时填写的FloorNum)
     * @author zhangs
     * @createDate 2017/11/21
     */
    private String getFloorByPOList(List<DeviceElevatorFloorConfigPO> deviceElevatorFloorConfigPOS) {
        StringBuffer floorBuffer = new StringBuffer();
        for (DeviceElevatorFloorConfigPO deviceElevatorFloorConfigPO:deviceElevatorFloorConfigPOS) {
            String logicalFloor = deviceElevatorFloorConfigPO.getLogicalFloor();
            if (StringUtils.isNotEmpty(logicalFloor)) {
                floorBuffer.append(logicalFloor).append(",");
            } else {
                Integer floorNum  = deviceElevatorFloorConfigPO.getFloorNum();
                if (floorNum != null) {
                    floorBuffer.append(floorNum).append(",");
                } else {
                    floorBuffer.append(deviceElevatorFloorConfigPO.getNaturalFloor()).append(",");
                }
            }
        }
        return StringHandlerUtil.clearComma(floorBuffer).toString();
    }

    /**
     * <desc>
     *      合并用户在单个项目中同类型的设备权限数据
     * <desc/>
     *
     * @param appUserGetDeviceAuthVOList 用户在单个项目中同类型的设备权限
     * @return List<AppUserGetDeviceAuthVO> 同类型合并之后的用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    private List<AppUserGetDeviceAuthVO> mergeSameTypeDeviceAuth(List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOList) {
        //合并整理后的设备权限集
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        //用于去重的设备唯一码list
        List<String> removeList = new ArrayList<>();
        if(appUserGetDeviceAuthVOList != null && appUserGetDeviceAuthVOList.size() > 0) {
            AppUserGetDeviceAuthVO appUserGetDeviceAuth;
            for(AppUserGetDeviceAuthVO appUserGetDeviceAuthVO:appUserGetDeviceAuthVOList) {
                //去重,在已有集合中是否重复及其对应角标
                int index = removeList.indexOf(appUserGetDeviceAuthVO.getDeviceUnique());
                if(index > -1) {
                    //有重复，取出已有集合中的数据做合并
                    appUserGetDeviceAuth = appUserGetDeviceAuthVOS.get(index);
                    //合并isChecked(前端使用)。由物业地址得到的设备权限无法更改，即以下两个设备中标记只要有一个为0即均为0
                    if((appUserGetDeviceAuth.getIsChecked() == PlatformConstants.DEVICEAUTH_ISCHECKED_NO) ||
                            (appUserGetDeviceAuthVO.getIsChecked() == PlatformConstants.DEVICEAUTH_ISCHECKED_NO)) {
                        appUserGetDeviceAuth.setIsChecked(PlatformConstants.DEVICEAUTH_ISCHECKED_NO);
                    }
                    //若是电梯设备则需合并楼层权限标识(naturalFloor)以及楼层(logicalFloor)
                    if(appUserGetDeviceAuthVO.getDeviceType().equals(String.valueOf(PropertyEquipTypeEnum.ELEVATOR.getType()))) {
                        //楼层权限标识(naturalFloor)
                        appUserGetDeviceAuth.setNaturalFloor(this.mergeFloorAtDevice(
                                appUserGetDeviceAuth.getNaturalFloor(), appUserGetDeviceAuthVO.getNaturalFloor()));
                        //楼层(logicalFloor)
                        appUserGetDeviceAuth.setLogicalFloor(this.mergeFloorAtDevice(
                                appUserGetDeviceAuth.getLogicalFloor(), appUserGetDeviceAuthVO.getLogicalFloor()));
                        //取出appUserGetDeviceAuthVO和appUserGetDeviceAuth中的tempFloor(非地址映射的电梯楼层(此处楼层指logicalFloor))
                        // 并做合并.再从合并后的tempFloor中去除合并后的appUserGetDeviceAuth中的logicalFloor，tempFloor中余
                        // 下的即为设备授权中电梯权限的可编辑楼层
                        String tempFloor = this.getElevatorTempFloor(appUserGetDeviceAuthVO.getTempFloor(),
                                appUserGetDeviceAuth.getTempFloor(), appUserGetDeviceAuth.getLogicalFloor());
                        if (StringUtils.isNotBlank(tempFloor)) {
                            appUserGetDeviceAuth.setTempFloor(tempFloor);
                        }
                    }
                    appUserGetDeviceAuthVOS.set(index, appUserGetDeviceAuth);
                } else {
                    //无重复
                    appUserGetDeviceAuthVOS.add(appUserGetDeviceAuthVO);
                    removeList.add(appUserGetDeviceAuthVO.getDeviceUnique());
                }
            }
        }
        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      合并相同电梯设备中非地址映射的权限楼层tempFloor，并去除tempFloor中已被标记的不可编辑的权限楼层logicalFloor，
     *      余下tempFloor即为可编辑的楼层权限
     * <desc/>
     *
     * @param tempFloor1 相同电梯设备中非地址映射的权限楼层tempFloor
     * @param tempFloor2 相同电梯设备中非地址映射的权限楼层tempFloor
     * @param logicalFloors 被标记的不可编辑的权限楼层logicalFloor
     * @return String 可编辑的楼层权限
     * @author zhangs
     * @createDate 2017/10/10
     */
    private String getElevatorTempFloor(String tempFloor1, String tempFloor2, String logicalFloors) {
        if (StringUtils.isBlank(logicalFloors)) {
            return "";
        }
        if (StringUtils.isBlank(tempFloor1) && StringUtils.isBlank(tempFloor2)) {
            return "";
        }
        Set<String> tempFloorSet = new HashSet<>();
        if (StringUtils.isNotBlank(tempFloor1)) {
            for (String string:tempFloor1.split(",")) {
                tempFloorSet.add(string);
            }
        }
        if (StringUtils.isNotBlank(tempFloor2)) {
            for (String string:tempFloor2.split(",")) {
                tempFloorSet.add(string);
            }
        }
        for (String logicalFloor:logicalFloors.split(",")) {
            tempFloorSet.remove(logicalFloor);
        }
        return StringUtils.join(tempFloorSet, ",");
    }

    /**
     * <desc>
     *      获得转换后的门禁设备权限(获取前端设备权限按钮可用的数据对象)
     * <desc/>
     *
     * @param authSource 设备权限来源标识(1:一卡通 2:物业后台)
     * @param deviceAuth 授权设备信息,自然数字符串
     * @param projectId 项目Id
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    private List<AppUserGetDeviceAuthVO> getConvertEntranceDeviceAuth(Integer authSource, StringBuffer deviceAuth, String projectId) {
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        if(deviceAuth == null) {
            return appUserGetDeviceAuthVOS;
        }
        AppUserGetDeviceAuthVO appUserGetDeviceAuthVO;

        //authSource:设备权限来源标识(1:一卡通 2:物业后台)
        //isChecked:能否被选中(0:已选中但无法更改 | 1:已选中且可以更改 | 2:未选中)
        Integer isChecked;
        //权限源于一卡通或物业后台临时授权的可以更改
        if(DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType().equals(authSource)
                || DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType().equals(authSource)) {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_YSE;
        } else {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_NO;
        }
        int index = 0;
        while(index < deviceAuth.length()) {
            //1~8中，门禁权限码除7(PlatformConstants.ENTRANCE_NOAUTHNUM)以外，其他均有权限，只是权限不同
            String authCode = StringHandlerUtil.copySubStr(deviceAuth.toString(), index, 1);
            if (StringHandlerUtil.compareStrWithOutEmpty(PlatformConstants.ENTRANCE_NOAUTHNUM, authCode)) {
                index++;
                continue;
            }
            //拼接设备唯一码：projectId+deviceType+deviceId
            StringBuffer deviceUnique = new StringBuffer(projectId).append(PropertyEquipTypeEnum.ENTRANCE.getType()).
                    append(String.format("%04d", ++index));
            appUserGetDeviceAuthVO = new AppUserGetDeviceAuthVO(deviceUnique.toString(), null, null,
                    String.valueOf(PropertyEquipTypeEnum.ENTRANCE.getType()), isChecked);
            appUserGetDeviceAuthVOS.add(appUserGetDeviceAuthVO);

            /*index = deviceAuth.indexOf(PlatformConstants.ENTRANCE_AUTHNUM, index);    //权限标识在权限字符串中的位置
            if(index > -1) {
                ++index;

                StringBuffer deviceUnique = new StringBuffer(projectId).
                        append(PropertyEquipTypeEnum.ENTRANCE.getType()).append(String.format("%04d", index));
                appUserGetDeviceAuthVO = new AppUserGetDeviceAuthVO(deviceUnique.toString(), null, null,
                        String.valueOf(PropertyEquipTypeEnum.ENTRANCE.getType()), isChecked);
                appUserGetDeviceAuthVOS.add(appUserGetDeviceAuthVO);
            } else {
                index = deviceAuth.length();
            }*/
        }

        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      获得转换后的云对讲设备权限
     * <desc/>
     *
     * @param authSource 设备权限来源标识(1:一卡通 2:物业后台)
     * @param deviceAuth 授权设备信息
     * @param projectId 项目Id
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    private List<AppUserGetDeviceAuthVO> getConvertCloudIntercomDeviceAuth(Integer authSource, String deviceAuth, String projectId) {
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        if(StringUtils.isBlank(deviceAuth)) {
            return appUserGetDeviceAuthVOS;
        }

        //authSource:设备权限来源标识(1:一卡通 2:物业后台)
        //isChecked:能否被选中
        Integer isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_YET;
        if(DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType().equals(authSource)
                || DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType().equals(authSource)) {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_YSE;
        } else {
            isChecked = PlatformConstants.DEVICEAUTH_ISCHECKED_NO;
        }
        String deviceType = String.valueOf(PropertyEquipTypeEnum.CLOUD_INTERCOM.getType());
        int index = 0;
        StringBuffer deviceAuths = new StringBuffer(StringHandlerUtil.getNaturalFloorsByAuthCode(deviceAuth));
        if(deviceAuths.length() == 0) {
            return appUserGetDeviceAuthVOS;
        }
        while(index < deviceAuth.length()) {
            //1~8中，门禁权限码除7(PlatformConstants.ENTRANCE_NOAUTHNUM)以外，其他均有权限，只是权限不同
            String authCode = StringHandlerUtil.copySubStr(deviceAuth.toString(), index, 1);
            if (StringHandlerUtil.compareStrWithOutEmpty(PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM, authCode)) {
                index++;
                continue;
            }
            StringBuffer deviceUnique = new StringBuffer(projectId).
                    append(PropertyEquipTypeEnum.CLOUD_INTERCOM.getType()).append(String.format("%04d", ++index));
            AppUserGetDeviceAuthVO appUserGetDeviceAuthVO = new AppUserGetDeviceAuthVO();
            appUserGetDeviceAuthVO.setDeviceUnique(deviceUnique.toString());
            appUserGetDeviceAuthVO.setIsChecked(isChecked);
            appUserGetDeviceAuthVO.setDeviceType(deviceType);
            appUserGetDeviceAuthVOS.add(appUserGetDeviceAuthVO);
//            index++;
        }

        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      合并相同电梯设备权限信息的楼层数据
     * <desc/>
     *
     * @param FloorSt 需合并的楼层信息
     * @param FloorNd 需合并的楼层信息
     * @return String 合并后的楼层数据
     * @author zhangs
     * @createDate 2017/10/10
     */
    private String mergeFloorAtDevice(String FloorSt, String FloorNd) {
        /*if((StringUtils.isBlank(FloorSt)) || (StringUtils.isBlank(FloorNd))) {
            return "";
        }*/
        Set<String> floorSet = new HashSet<>();
        if (StringUtils.isNotBlank(FloorSt)) {
            Collections.addAll(floorSet, FloorSt.split(","));
        }
        if (StringUtils.isNotBlank(FloorNd)) {
            Collections.addAll(floorSet, FloorNd.split(","));
        }
        StringBuffer stringBuffer = new StringBuffer();
        for (Object aFloorSet : floorSet) {
            stringBuffer.append(aFloorSet).append(",");
        }
        return StringHandlerUtil.clearComma(stringBuffer).toString();
    }

    /**
     * <desc>
     *      物业地址授权-清除用户在当前小区设备权限
     * <desc/>
     * @param userId 授权人ID，可能为用户id也可能为物业账号id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 用户设备权限来源
     * @param jPushMessage  极光推送信息
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Override
    public void deleteUserPropertyDeviceAuth(
            String authUserId,
            String userId,
            String projectId,
            Integer authSource,
            String jPushMessage) throws Exception {
        if((StringUtils.isBlank(userId)) || (StringUtils.isBlank(projectId))) {
            return;
        }

        //清除用户在当前小区设备权限(电梯/门禁/云对讲)
        this.delUserDeviceAuth(userId, projectId, authSource, authUserId);

        //更新redis中的用户设备权限
        try {
            updateUserDeviceAuthAtRedis(userId, projectId,true, jPushMessage);
        } catch (Exception e) {
            LOG.error(String.format("【物业系统_更新redis中用户设备权限信息出错_updateUserDeviceAuthAtRedis()】" +
                    "info:{%s, %s}", userId, projectId), e);
        }
    }

    /**
     * <desc>
     *      清除用户在当前小区设备权限
     * <desc/>
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 用户设备权限来源
     * @param authUserId 授权人ID，可能为用户id也可能为物业账号id
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void delUserDeviceAuth(String userId, String projectId, Integer authSource, String authUserId) throws Exception {
        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        param.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            param.put("authUserId", authUserId);
        }
        //清除住户在当前小区的电梯设备权限
        iPropertyDeviceAuthElevatorAuthDao.delByParam(param);
        //清除住户在当前小区的门禁设备权限
        iPropertyDeviceAuthEntranceAuthDao.delByParam(param);
        //清除住户在当前小区的云对讲设备权限
        iPropertyDeviceAuthCloudIntercomAuthDao.delByParam(param);
    }

    /**
     * <desc>
     *      物业地址授权-清除用户在当前小区设备权限
     * <desc/>
     * @param userId 授权人ID，可能为用户id也可能为物业账号id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 用户设备权限来源
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteUserDeviceAuth(
            String authUserId,
            String userId,
            String projectId,
            Integer authSource) throws Exception {
        if((StringUtils.isBlank(userId)) || (StringUtils.isBlank(projectId))) {
            return;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("projectId", projectId);
        param.put("userId", userId);
        param.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            param.put("authUserId", authUserId);
        }
        //清除住户在当前小区的电梯设备权限
        iPropertyDeviceAuthElevatorAuthDao.delByParam(param);
        //清除住户在当前小区的门禁设备权限
        iPropertyDeviceAuthEntranceAuthDao.delByParam(param);
        //清除住户在当前小区的云对讲设备权限
        iPropertyDeviceAuthCloudIntercomAuthDao.delByParam(param);
    }



    /**
     * <desc>
     *      获取无权限时的设备权限
     * <desc/>
     * @param deviceCount 设备数量
     * @param noAuthNum 无权限码
     * @return String
     * @author zhangs
     * @createDate 2017/10/10
     */
    private String getNoAuthDeviceAuth(Integer deviceCount, String noAuthNum) {
        String noAuthDeviceAuth = "";
        StringBuffer deviceAuthBuffer = new StringBuffer();
        if((deviceCount == null) || (StringUtils.isEmpty(noAuthNum))) {
            return noAuthDeviceAuth;
        }
        for(int i = 0;i < deviceCount;i++) {
            deviceAuthBuffer.append(noAuthNum);
        }
        noAuthDeviceAuth = StringHandlerUtil.clearComma(deviceAuthBuffer).toString();
        return noAuthDeviceAuth;
    }

    /**
     * <desc>
     *      迁出住户时删除地址对应的其他类别的设备权限
     * <desc/>
     * @param   userDeviceAuthAddreddDTOS  地址信息集
     * @return
     * @author zhangs
     * @createDate 2017/11/2
     */
    @Override
    public void delUserOtherAuth(@RequestBody List<UserDeviceAuthAddreddDTO> userDeviceAuthAddreddDTOS)throws Exception {
        if(userDeviceAuthAddreddDTOS == null || (userDeviceAuthAddreddDTOS != null && userDeviceAuthAddreddDTOS.size() < 1)) {
            return;
        }
        for(UserDeviceAuthAddreddDTO userDeviceAuthAddreddDTO:userDeviceAuthAddreddDTOS) {
            AppUserDeviceAuthsVO appUserDeviceAuthsVO = iPropertyEquipService.getEquipByAddress(userDeviceAuthAddreddDTO);
            String authUserId = appUserDeviceAuthsVO.getAuthUserId();
            String userId = appUserDeviceAuthsVO.getUserId();
            String projectId = appUserDeviceAuthsVO.getProjectId();
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = appUserDeviceAuthsVO.getAppUserGetDeviceAuthVOS();
            this.deleteAuthByRemoveAddr(authUserId, userId, projectId, appUserGetDeviceAuthVOS);
        }
    }

    /**
     * <desc>
     *      用户设备权限-迁出时删除地址对应的一卡通权限
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @return
     * @author zhangs
     * @createDate 2017/10/24
     */
    public void deleteAuthByRemoveAddr(
            String authUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS) throws Exception{
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) ||
                (appUserGetDeviceAuthVOS == null) || (appUserGetDeviceAuthVOS != null && appUserGetDeviceAuthVOS.size() < 1)) {
            return ;
        }

        //从原有的其他类型权限中删除对应设备权限(电梯/门禁/云对讲)
        this.delAppointDeviceAuthByExistAuth(authUserId, userId, projectId, appUserGetDeviceAuthVOS);

        //更新redis中的用户设备权限
        try {
            updateUserDeviceAuthAtRedis(userId, projectId,true, null);
        } catch (Exception e) {
            LOG.error(String.format("【物业系统_更新redis中用户设备权限信息出错_updateUserDeviceAuthAtRedis()】" +
                    "info:{%s, %s}", userId, projectId), e);
        }
    }

    /**
     * <desc>
     *      从原有的其他类型权限中删除对应设备权限
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @return
     * @author zhangs
     * @createDate 2018/02/26
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void delAppointDeviceAuthByExistAuth(
            String authUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS) throws Exception {
        StringBuffer elevatorDevice = new StringBuffer();
        StringBuffer naturalFloorBuffer = new StringBuffer();
        StringBuffer entranceDevice = new StringBuffer();
        StringBuffer cloudDevice = new StringBuffer();
        for(AppUserGetDeviceAuthVO appUserGetDeviceAuthVO:appUserGetDeviceAuthVOS) {
            String deviceType = appUserGetDeviceAuthVO.getDeviceType();
            String deviceUnique = appUserGetDeviceAuthVO.getDeviceUnique();
            if (!StringUtils.isNumeric(deviceType)) {
                continue;
            }
            switch(Integer.parseInt(deviceType)) {
                case DEVICEAUTH_DEVICETYPE_ELEVATOR:
                    String naturalFloor = appUserGetDeviceAuthVO.getNaturalFloor();
                    elevatorDevice.append(deviceUnique).append(",");
                    //楼层权限转为二进制方便去除时比较
                    naturalFloorBuffer.append(StringHandlerUtil.hexToBinary(StringHandlerUtil.getAuthCodeBynNturalFloors(naturalFloor))).append(",");
                    break;
                case DEVICEAUTH_DEVICETYPE_ENTRANCE:
                    entranceDevice.append(deviceUnique).append(",");
                    break;
                case DEVICEAUTH_DEVICETYPE_CLOUDINTERCOM:
                    cloudDevice.append(deviceUnique).append(",");
                    break;
                default:
                    LOG.info(String.format("【物业系统_更新用户设备权限出错_updateUserDeviceAuth()】info:{%s}", appUserGetDeviceAuthVO));
                    break;
            }
        }

        if((elevatorDevice.length() > 0) && (naturalFloorBuffer.length() > 0)) {
            //从原有的其他类型权限中删除对应电梯设备权限
            this.deleteElevatorAuthByRemoveAddr(
                    authUserId, userId, projectId, elevatorDevice, naturalFloorBuffer, DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType());
        }
        if(entranceDevice.length() > 0) {
            //从原有的其他类型权限中删除对应门禁设备权限
            this.deleteEntranceAuthByRemoveAddr(
                    authUserId, userId, projectId, entranceDevice, DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType());
        }
        if(cloudDevice.length() > 0) {
            //从原有的其他类型权限中删除对应云对讲设备权限
            this.deleteCloudAuthByRemoveAddr(
                    authUserId, userId, projectId, cloudDevice, DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType());
        }
    }

    /**
     * <desc>
     *      从原有的其他类型权限中删除对应电梯设备权限
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param elevatorDevice 电梯设备唯一码字符串
     * @param naturalFloorBuffer 楼层字符串
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    private void deleteElevatorAuthByRemoveAddr(
            String authUserId,
            String userId,
            String projectId,
            StringBuffer elevatorDevice,
            StringBuffer naturalFloorBuffer,
            Integer authSource) {
        if((elevatorDevice == null || elevatorDevice.length() == 0) ||
                (naturalFloorBuffer == null || naturalFloorBuffer.length() == 0)) {
            return;
        }
        //设备唯一码数组
        String[] elevatorDeviceArr = StringHandlerUtil.clearComma(elevatorDevice).toString().split(",");
        //楼层权限(二进制式)数组
        String[] naturalFloorArr = StringHandlerUtil.clearComma(naturalFloorBuffer).toString().split(",");

        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
//        params.put("authSource", authSource);
        params.put("tempAuth", DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
        params.put("smartCardAuth", DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            params.put("authUserId", authUserId);
        }
        //获取用户旧的临时设备权限信息(物业临时和一卡通)
//        List<DeviceElevatorAuthPO> deviceElevatorAuthPOS = iPropertyDeviceAuthElevatorAuthDao.getUserDeviceElevatorAuth(params);
        List<DeviceElevatorAuthPO> deviceElevatorAuthPOS = iPropertyDeviceAuthElevatorAuthDao.getUserTempDeviceAuth(params);
        if(deviceElevatorAuthPOS.size() == 0) {
            return;
        }

        //遍历单个用户的权限
        for(DeviceElevatorAuthPO deviceElevatorAuthPO:deviceElevatorAuthPOS) {
            //设备二进制字符串
            String deviceAuth = deviceElevatorAuthPO.getDeviceAuth();
            //楼层十六进制数组
            String floorAuths = deviceElevatorAuthPO.getFloorAuth();
            String[] floorAuthArr = floorAuths.split(",");
            //存储最终的电梯设备权限码
            StringBuffer deviceAuthBuffer = new StringBuffer(deviceAuth);
            //存储最终的楼层权限码
            StringBuffer floorAuthBuffer = new StringBuffer();

            int index;
            //遍历需要去掉权限的设备
            for (int deviceIndex = 0;deviceIndex < elevatorDeviceArr.length;deviceIndex++) {
//            for(String elevatorDeviceUnique:elevatorDeviceArr) {
                String elevatorDeviceUnique = elevatorDeviceArr[deviceIndex];
                //获取设备机号
                String deviceId = StringHandlerUtil.copySubStr(elevatorDeviceUnique, 9, 4);
                if (!StringUtils.isNumeric(deviceId)) {
                    continue;
                }
                //设备在权限码deviceAuth中的位置
                index = Integer.parseInt(deviceId);
                if(PlatformConstants.ELEVATOR_AUTHNUM.equals(String.valueOf(deviceAuth.charAt(index - 1)))) {
                    if (deviceIndex < naturalFloorArr.length) {
                        //需要去掉的楼层(二进制)
                        String naturalFloor = naturalFloorArr[deviceIndex];
                        //需要修改的楼层在数组中的角标
                        int foot = this.getIndex(deviceAuth.substring(0, index), PlatformConstants.ELEVATOR_AUTHNUM);
                        //需要修改的楼层(二进制)
                        String floorAuth = StringHandlerUtil.hexToBinary(floorAuthArr[foot - 1]);
                        if(StringUtils.isNotBlank(floorAuth)) {
                            StringBuffer stringBuffer = new StringBuffer(floorAuth);
                            for(int j = 0;j<naturalFloor.length();j++) {
                                if((naturalFloor.charAt(j) == '1') && (floorAuth.charAt(j) == '1')) {
                                    stringBuffer.setCharAt(j, '0');
                                }
                            }
                            floorAuth = stringBuffer.toString();
                            //若某电梯上楼层全部去掉，则对应楼层数组须置空，设备二进制字符串对应设备置0
                            if((StringUtils.isBlank(floorAuth)) || (floorAuth.indexOf('1') < 0)) {
                                floorAuthArr[foot - 1] = "";
                                deviceAuthBuffer.setCharAt(index - 1, '0');
                            } else {
                                floorAuthArr[foot - 1] = StringHandlerUtil.binaryToHex(floorAuth);
                            }
                        }
                    }
                }
            }
            for (String aFloorAuthArr : floorAuthArr) {
                if (StringUtils.isNotBlank(aFloorAuthArr)) {
                    floorAuthBuffer.append(aFloorAuthArr).append(",");
                }
            }
            String deviceAuthCode = deviceAuthBuffer.toString();
            String floorAuthCode = StringHandlerUtil.clearComma(floorAuthBuffer).toString();
            if ((deviceAuthCode.indexOf('1') < 0) || (StringUtils.isBlank(floorAuthCode))) {
                //删除
                Map<String, Object> param = new HashMap<>();
                param.put("userId", deviceElevatorAuthPO.getUserId());
                param.put("projectId", deviceElevatorAuthPO.getProjectId());
                param.put("authUserId", deviceElevatorAuthPO.getAuthUserId());
                param.put("authSource", deviceElevatorAuthPO.getAuthSource());
                iPropertyDeviceAuthElevatorAuthDao.delByParam(param);
            } else {
                //更新
                deviceElevatorAuthPO.setDeviceAuth(deviceAuthBuffer.toString());
                deviceElevatorAuthPO.setFloorAuth(StringHandlerUtil.clearComma(floorAuthBuffer).toString());
                deviceElevatorAuthPO.setUpdateTime(new Date());
                if (StringUtils.isNotBlank(authUserId)) {
                    deviceElevatorAuthPO.setAuthUserId(authUserId);
                }
                iPropertyDeviceAuthElevatorAuthDao.update(deviceElevatorAuthPO);
            }
        }
    }

    /**
     * <desc>
     *      获取某个标识在一段字符串中出现的次数
     * <desc/>
     *
     * @param string 需要检测的字符串
     * @param sign 需要检测的标识
     * @return int 数目
     * @author zhangs
     * @createDate 2017/10/10
     */
    private int getIndex(String string, String sign) {
        int index = 0;
        for(int j = 0;j < string.length();j++) {
            if(sign.equals(String.valueOf(string.charAt(j)))) {
                index++;
            }
        }
        return index;
    }

    /**
     * <desc>
     *      从原有的其他类型权限中删除对应门禁设备权限
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param entranceDevice 电梯设备唯一码字符串
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    private void deleteEntranceAuthByRemoveAddr(
            String authUserId,
            String userId,
            String projectId,
            StringBuffer entranceDevice,
            Integer authSource) {
        if((entranceDevice == null || entranceDevice.length() == 0)) {
            return;
        }
        //设备唯一码数组
        String[] entranceDeviceArr = StringHandlerUtil.clearComma(entranceDevice).toString().split(",");

        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
//        params.put("authSource", authSource);
        params.put("tempAuth", DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
        params.put("smartCardAuth", DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            params.put("authUserId", authUserId);
        }
        //获取用户旧的临时设备权限信息(物业后台临时和一卡通)
        List<DeviceEntranceAuthPO> deviceEntranceAuthPOS = iPropertyDeviceAuthEntranceAuthDao.getUserTempDeviceEntranceAuth(params);
//        List<DeviceEntranceAuthPO> deviceEntranceAuthPOS = iPropertyDeviceAuthEntranceAuthDao.getUserDeviceEntranceAuth(params);
        if(deviceEntranceAuthPOS.size() == 0) {
            return;
        }

        //遍历单个用户的权限
        for(DeviceEntranceAuthPO deviceEntranceAuthPO:deviceEntranceAuthPOS) {
            String deviceAuth = deviceEntranceAuthPO.getDeviceAuth();

            int index;
            StringBuffer stringBuffer = new StringBuffer(deviceAuth);
            //遍历获取设备唯一码
            for(String entranceDeviceUnique:entranceDeviceArr) {
                //获取授权设备信息字符串中的位置
                String position = StringHandlerUtil.copySubStr(entranceDeviceUnique, 9, 4);
                if (!StringUtils.isNumeric(position)) {
                    continue;
                }
                index = Integer.parseInt(position);
                //1~8中，门禁权限码除7以外，其他均有权限，只是权限不同
                if(!PlatformConstants.ENTRANCE_NOAUTHNUM.equals(String.valueOf(deviceAuth.charAt(index - 1)))) {
                    stringBuffer.setCharAt(index - 1, PlatformConstants.ENTRANCE_NOAUTHNUM.charAt(0));
                }
            }
            deviceAuth = stringBuffer.toString();
            deviceEntranceAuthPO.setDeviceAuth(deviceAuth);
            deviceEntranceAuthPO.setAuthUserId(authUserId);
            deviceEntranceAuthPO.setUpdateTime(new Date());
            iPropertyDeviceAuthEntranceAuthDao.updateById(deviceEntranceAuthPO);
        }
    }

    /**
     * <desc>
     *      从原有的其他类型权限中删除对应云对讲设备权限
     * <desc/>
     *
     * @param authUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param cloudDevice 电梯设备唯一码字符串
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    private void deleteCloudAuthByRemoveAddr(
            String authUserId,
            String userId,
            String projectId,
            StringBuffer cloudDevice,
            Integer authSource) {
        if((cloudDevice == null || cloudDevice.length() == 0)) {
            return;
        }
        //设备唯一码数组
        String[] cloudDeviceArr = StringHandlerUtil.clearComma(cloudDevice).toString().split(",");

        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource", authSource);
        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
            params.put("authUserId", authUserId);
        }
        //获取用户旧的设备权限信息
        List<DeviceCloudIntercomAuthPO> deviceEntranceAuthPOS = iPropertyDeviceAuthCloudIntercomAuthDao.getUserDeviceCloudIntercomAuth(params);
        if(deviceEntranceAuthPOS.size() == 0) {
            return;
        }

        //遍历单个用户的权限
        for(DeviceCloudIntercomAuthPO deviceCloudIntercomAuthPO:deviceEntranceAuthPOS) {
            String deviceAuth = deviceCloudIntercomAuthPO.getDeviceAuth();
            if(StringUtils.isNotBlank(deviceAuth)) {
                int index;
                StringBuffer stringBuffer = new StringBuffer(deviceAuth);
                for(String cloudDeviceUnique:cloudDeviceArr) {
                    //获取授权设备信息字符串中的位置
                    String position = StringHandlerUtil.copySubStr(cloudDeviceUnique, 9, 4);
                    if (!StringUtils.isNumeric(position)) {
                        continue;
                    }
                    index = Integer.parseInt(position);
                    if(!PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM.equals(String.valueOf(deviceAuth.charAt(index - 1)))) {
                        stringBuffer.setCharAt(index - 1, PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM.charAt(0));
                    }
                }
                deviceAuth = stringBuffer.toString();
                deviceCloudIntercomAuthPO.setDeviceAuth(deviceAuth);
                deviceCloudIntercomAuthPO.setAuthUserId(authUserId);
                deviceCloudIntercomAuthPO.setUpdateTime(new Date());
                iPropertyDeviceAuthCloudIntercomAuthDao.updateById(deviceCloudIntercomAuthPO);
            }
        }
    }

    /**
     * <desc>
     *      设备授权-更新用户设备权限
     * <desc/>
     *
     * @param loginUserId 用户登录Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Override
    public Integer updateSmartCardUserDeviceAuth(
            String loginUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS) throws Exception{
        deviceAuthServiceThreadPool.execute(
                () -> {
                    try {
                        updateSmartCardUserDeviceAuthInThread(projectId, userId, projectId, appUserGetDeviceAuthVOS);
                    } catch (Exception e) {
                        LOG.error(String.format("更新一卡通用户权限失败:%s-%s,%s",projectId,userId,JSON.toJSONString(appUserGetDeviceAuthVOS)), e);
                    }
                });
        return 1;

    }

    /**
     * <desc>
     * 设备授权-更新用户设备权限
     * <desc/>
     *
     * @param loginUserId             用户登录Id
     * @param userId                  用户Id
     * @param projectId               项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Override
    public Integer updateSmartCardUserDeviceAuthInThread(
            String loginUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS) throws Exception {

        Integer result = 0;
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) || appUserGetDeviceAuthVOS.size() == 0) {
            return result;
        }

        //更新用户设备权限信息(电梯/门禁/云对讲)
        result = this.updateSmartCardUserDeviceAuthToDB(loginUserId, userId, projectId, appUserGetDeviceAuthVOS);

        //更新redis中的用户设备权限
        try {
            updateUserDeviceAuthAtRedis(userId, projectId,false, null);
        } catch (Exception e) {
            LOG.error(String.format("【物业系统_更新redis中用户设备权限信息出错_updateUserDeviceAuthAtRedis()】" +
                    "info:{%s, %s}", userId, projectId), e);
        }
        return result;

    }

    /**
     * <desc>
     *      更新用户设备权限信息
     * </desc>
     *
     * @@param loginUserId             用户登录Id
     * @param userId                  用户Id
     * @param projectId               项目Id
     * @param appUserGetDeviceAuthVOS 用户设备权限信息
     * @return Integer 影响的数据数量
     * @author zhangs
     * @createDate 2018/02/26
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer updateSmartCardUserDeviceAuthToDB(
            String loginUserId,
            String userId,
            String projectId,
            List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS ) throws Exception {
        Integer result = 0;
        Map<String, Object> deviceMap = this.getMergeDeviceUnique(appUserGetDeviceAuthVOS);
        StringBuffer elevatorDevice;
        elevatorDevice = (StringBuffer) deviceMap.get("elevatorDevice");
        StringBuffer naturalFloorBuffer;
        naturalFloorBuffer = (StringBuffer) deviceMap.get("naturalFloorBuffer");
        StringBuffer entranceDevice;
        entranceDevice = (StringBuffer) deviceMap.get("entranceDevice");
        StringBuffer cloudDevice;
        cloudDevice = (StringBuffer) deviceMap.get("cloudDevice");

        int elevatorCount = PlatformConstants.MAX_ELEVATOR_DEVICEID;
        int entranceCount = PlatformConstants.MAX_ENTRANCE_DEVICEID;
        int cloudCount = PlatformConstants.MAX_CLOUD_INTERCOM_DEVICEID;
        if((elevatorDevice.length() > 0) && (naturalFloorBuffer.length() > 0)) {
            //更新用户电梯设备权限信息
            result += this.updateUserDeviceElevator(
                    loginUserId, userId, projectId, elevatorDevice, naturalFloorBuffer, elevatorCount, DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
            //同步更新物业临时权限
            List<DeviceElevatorAuthPO> oldTmpElevatorAuths = this.getDeviceElevatorAuthFromDB(projectId,userId,DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
            if ((null != oldTmpElevatorAuths) && (!oldTmpElevatorAuths.isEmpty())){
                result += this.updateUserDeviceElevator(
                        loginUserId, userId, projectId, elevatorDevice, naturalFloorBuffer, elevatorCount, DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
            }
        }else if (elevatorDevice.length() <= 0)
        {
            result += this.deleteSmartCardAuth(userId,projectId,PropertyEquipTypeEnum.ELEVATOR);
        }
        if(entranceDevice.length() > 0) {
            //更新用户门禁设备权限信息
            result += this.updateUserDeviceEntrance(
                    loginUserId, userId, projectId, entranceDevice, entranceCount, DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
            List<DeviceEntranceAuthPO> oldTmpEntranceAuths =
                    this.getDeviceEntranceAuthFromDB(projectId,userId,DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
            if ((null != oldTmpEntranceAuths) && (!oldTmpEntranceAuths.isEmpty())){
                //同步更新物业临时权限
                result += this.updateUserDeviceEntrance(
                        loginUserId, userId, projectId, entranceDevice, entranceCount, DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
            }
        } else
        {
            result += this.deleteSmartCardAuth(userId,projectId,PropertyEquipTypeEnum.ENTRANCE);
        }
        if(cloudDevice.length() > 0) {
            //更新用户云对讲设备权限信息
            result += this.updateUserDeviceCloud(
                    loginUserId, userId, projectId, cloudDevice, cloudCount, DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
            result += this.updateUserDeviceCloud(
                    loginUserId, userId, projectId, cloudDevice, cloudCount, DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType());
        } else{
            result += this.deleteSmartCardAuth(userId,projectId,PropertyEquipTypeEnum.CLOUD_INTERCOM);
        }
        return result;
    }

    /**
    * <desc>
    *    删除指定用户指定项目的一卡通权限.
    * </desc>
    *
    * @param  userId 用户Id
     * @param  projectId 项目Id
     *   @param euquiType 设备类型
    * @return 受影响的行数
    * @author LewisLouis
    * @createDate 2018-02-07
    */
    private int deleteSmartCardAuth(String userId,String projectId,PropertyEquipTypeEnum euquiType){
        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("projectId", projectId);
        param.put("authSource", DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
        int intRes = 0;
        switch (euquiType){
            case ELEVATOR:   //清除住户在当前小区的电梯设备权限
                intRes = iPropertyDeviceAuthElevatorAuthDao.delByParam(param);
                break;
            case ENTRANCE:
                //清除住户在当前小区的门禁设备权限
                intRes = iPropertyDeviceAuthEntranceAuthDao.delByParam(param);
                break;
            case CLOUD_INTERCOM:
                //清除住户在当前小区的云对讲设备权限
                intRes = iPropertyDeviceAuthCloudIntercomAuthDao.delByParam(param);
                break;
        }
        return  intRes;



    }

    /**
     * <desc>
     *      家半径临时授权（包括住户管理设备授权和家半径一卡通用户授权）设备授权-更新用户临时设备权限(物业设备授权按钮。临时：物业临时和一卡通)
     *      前端页面只能一次传一个页面的数据，传当前页面所有设备以及勾选上的设备(电梯设备还需传楼层信息)
     * <desc/>
     *
     * @param loginUserId 用户登录Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param deviceType 设备类型
     * @param currentDevices 当前页面所有设备唯一码，以英文逗号拼接
     * @param selectDevices 当前页面所有选中设备唯一码，以英文逗号拼接
     * @param naturalfloorList 选中电梯设备时传输的楼层信息
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Override
    public void updateHouseHoldTmpDeviceAuth(
            String loginUserId,
            String userId,
            String projectId,
            Integer deviceType,
            String currentDevices,
            String selectDevices,
            List<String> naturalfloorList,
            String mark) throws Exception {
        if (StringUtils.isBlank(loginUserId) || StringUtils.isBlank(userId) || StringUtils.isBlank(projectId)
                ||  deviceType == null || StringUtils.isEmpty(currentDevices)) {
            return;
        }
        /*if ((deviceType == PropertyEquipTypeEnum.ELEVATOR.getType()) && (naturalfloorList.isEmpty())) {
            return;
        }*/

        //住户的权限若由物业后台(含临时)授权，则不关心授权人,住户的设备权限来源于物业后台的应只有一条(后台和后台临时分别一条)
//        if ((authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY.getType()) && (authSource != DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType())) {
//            params.put("authUserId", loginUserId);
//        }
        //设备分类更新权限
        switch (deviceType) {
            case DEVICEAUTH_DEVICETYPE_ELEVATOR:
                //保存或更新电梯设备临时权限
                this.saveOrUpdateTmpPropertyElevatorAuth(loginUserId, userId, projectId, currentDevices,
                        selectDevices, naturalfloorList, mark);

                break;
            case DEVICEAUTH_DEVICETYPE_ENTRANCE:

                //保存或更新门禁设备临时权限
                this.saveOrUpdateTmpPropertyEntranceAuth(loginUserId, userId, projectId, currentDevices,
                        selectDevices,mark);

                break;
            case DEVICEAUTH_DEVICETYPE_CLOUDINTERCOM:

                //保存或更新云对讲设备临时权限
                this.saveOrUpdateTmpPropertyCloudIntercomAuth(loginUserId, userId, projectId, currentDevices,
                        selectDevices);
                break;
            default:
                LOG.info(String.format("【物业系统_设备授权_更新用户临时设备权限】"));
                break;
        }
        //更新redis中的用户设备权限
        try {
            updateUserDeviceAuthAtRedis(userId, projectId,true, null);
        } catch (Exception e) {
            LOG.error(String.format("【物业系统_更新redis中用户设备权限信息出错_updateUserDeviceAuthAtRedis()】" +
                    "info:{%s, %s}", userId, projectId), e);
        }
        List<String> userIdList = new ArrayList<>();
        //如果临时授权的设备是电梯和门禁则向C#推送增量用户权限变更 前提是授权用户所在的项目的已启用人脸且用户是已注册过人脸
        //if(iPropertyDeviceAuthElevatorAuthDao.isFaceUser(userId,projectId)>0 && iSmartCardFaceDao.isStartFaceByProjectId(projectId)>0){
        //    userIdList.add(userId);
        //    //发送C#人脸识别用户权限变更增量推送指令
        //    Map<String,Object> data = new HashMap<>();
        //    SmartCardUserAuthPushDTO authPushDTO = new SmartCardUserAuthPushDTO();
        //    authPushDTO.setProjectId(projectId);
        //    authPushDTO.setUserIdList(userIdList);

        //    data.put("data",authPushDTO);
        //    messageSender.send(RabbitMQConstant.RABBITMQ_SMARTCARD_FACE_USER_AUTH_CHANGE_PUSH_QUEUE,
        //            JsonUtil.toJSON(data), RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
        //            RabbitMQConstant.RABBITMQ_SMARTCARD_FACE_USER_AUTH_CHANGE_PUSH_KEY);
        //}
    }

    /**
    * <desc>
    *     保存更新物业临时权限.
    * </desc>
    *
    * @param loginUserId 授权人Id
     * @param userId 用户Id
     * @param projectId 项目Id
    * @param currentDevices 本次操作的设备范围
    * @param selectDevices 勾选的设备列表
     * @param naturalFloors 勾选的设备对应的楼层权限标识列表，单个设备的楼层使用逗号分隔
     * @param mark 区分是否是住户分组授权或物业临时授权
    * @return
    * @author LewisLouis
    * @createDate 2018-01-03
    */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveOrUpdateTmpPropertyElevatorAuth(String loginUserId,
                                                     String userId,
                                                     String projectId,
                                                     String currentDevices,
                                                     String selectDevices,
                                                     List<String> naturalFloors,
                                                    String mark) throws  Exception{

        Integer authSource = DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType();
        if ("mark".equals(mark)) {
            authSource = DeviceAuthEnum.DEVICEAUTH_HOUSEHOLD_ROLE.getType();
        }
        //获取已有的物业临时设备权限
        List<DeviceElevatorAuthPO> oldTmpElevatorAuths = this.getDeviceElevatorAuthFromDB(projectId,userId,authSource);

        //本次选中的设备权限Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>
        Map<String,String> selectedElevatorAuthMap = convertSelectedElevatorAuthsToMap(selectDevices,naturalFloors,mark);
        //数据中已有的临时设备权限Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>
        Map<String,String> oldTmpElevatorAuthMap = convertOldTmpElevatorAuthToMap(oldTmpElevatorAuths);
        //更新后的临时设备权限Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>
        Map<String,String> newTmpElevatorAuthMap = new HashMap<>(oldTmpElevatorAuthMap);
        List<String> currentDevicesList =  Arrays.asList(currentDevices.split(","));
        for (String oneCurrentDeviceUnique:currentDevicesList){
            //本次选中的设备，一定有权限
            if (selectedElevatorAuthMap.containsKey(oneCurrentDeviceUnique)){
                newTmpElevatorAuthMap.put(oneCurrentDeviceUnique,selectedElevatorAuthMap.get(oneCurrentDeviceUnique));
            } else{
                //本次未选中的设备，若原来有，则需删除
                if (oldTmpElevatorAuthMap.containsKey(oneCurrentDeviceUnique)){
                    newTmpElevatorAuthMap.remove(oneCurrentDeviceUnique);
                }
            }
        }

        DeviceElevatorAuthPO deviceElevatorAuthPO =  convertNewTmpElevatorAuthToMapToPO(newTmpElevatorAuthMap);
        Date date = new Date();

        //若已有的物业临时设备权限，则更新，无则添加
        if ((null == oldTmpElevatorAuths) || oldTmpElevatorAuths.isEmpty()){
            if (StringUtils.isNotBlank(deviceElevatorAuthPO.getDeviceAuth()) &&
                    StringUtils.isNotBlank(deviceElevatorAuthPO.getFloorAuth())) {
                deviceElevatorAuthPO.setUserId(userId);
                deviceElevatorAuthPO.setProjectId(projectId);
                deviceElevatorAuthPO.setValiTime(DateUtil.fomatLongDate("2099-12-31 23:59:59"));
                deviceElevatorAuthPO.setAuthSource(authSource);
                deviceElevatorAuthPO.setAuthUserId(loginUserId);
                deviceElevatorAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
                deviceElevatorAuthPO.setCreateTime(date);
                deviceElevatorAuthPO.setUpdateTime(date);
                iPropertyDeviceAuthElevatorAuthDao.save(SqlUtil.durableData(deviceElevatorAuthPO, PlatformConstants.TABLE_SAVE));
            }
        } else {
            //电梯权限不为空且楼层不为空时更新，否则清除数据
            if (StringUtils.isBlank(deviceElevatorAuthPO.getDeviceAuth()) ||
                    StringUtils.isBlank(deviceElevatorAuthPO.getFloorAuth())) {
                iPropertyDeviceAuthElevatorAuthDao.deleteById(String.valueOf(oldTmpElevatorAuths.get(0).getId()));
            } else {
                DeviceElevatorAuthPO deviceElevatorAuthPOForUpdate = oldTmpElevatorAuths.get(0);
                deviceElevatorAuthPOForUpdate.setDeviceAuth(deviceElevatorAuthPO.getDeviceAuth());
                deviceElevatorAuthPOForUpdate.setFloorAuth(deviceElevatorAuthPO.getFloorAuth());
                deviceElevatorAuthPOForUpdate.setAuthUserId(loginUserId);
                deviceElevatorAuthPOForUpdate.setUpdateTime(new Date());
                iPropertyDeviceAuthElevatorAuthDao.update(deviceElevatorAuthPOForUpdate);
            }
        }

       //若存在一卡通权限，则直接同步更新
        List<DeviceElevatorAuthPO> oldSmartCardDeviceElevatorAuthPOS
                = this.getDeviceElevatorAuthFromDB(projectId,userId, DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
        //iPropertyDeviceAuthElevatorAuthDao.getUserDeviceElevatorAuth(params);
        if ((oldSmartCardDeviceElevatorAuthPOS != null) && (!oldSmartCardDeviceElevatorAuthPOS.isEmpty())) {
            DeviceElevatorAuthPO smartCardDeviceElevatorAuthPO = oldSmartCardDeviceElevatorAuthPOS.get(0);
            smartCardDeviceElevatorAuthPO.setDeviceAuth(deviceElevatorAuthPO.getDeviceAuth());
            smartCardDeviceElevatorAuthPO.setFloorAuth(deviceElevatorAuthPO.getFloorAuth());
            deviceElevatorAuthPO.setUpdateTime(new Date());
            iPropertyDeviceAuthElevatorAuthDao.update(smartCardDeviceElevatorAuthPO);
        }
    }

    /**
    * <desc>
    *     获取数据库中指定用户指定项目指定权限来源的电梯权限.
    * </desc>
    *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 权限来源 如  DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType()
    * @return 数据库中已有的电梯权限
    * @author LewisLouis
    * @createDate 2018-01-03
    */
    private List<DeviceElevatorAuthPO> getDeviceElevatorAuthFromDB(String projectId, String userId, Integer authSource){
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource",authSource);

        List<DeviceElevatorAuthPO> deviceElevatorAuthPOSInDB =
                iPropertyDeviceAuthElevatorAuthDao.getUserDeviceElevatorAuth(params);


        return deviceElevatorAuthPOSInDB;
    }


    /**
     * <desc>
     *     获取数据库中指定用户指定项目指定权限来源的门禁权限.
     * </desc>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 权限来源 如  DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType()
     * @return 数据库中已有的门禁权限
     * @author LewisLouis
     * @createDate 2018-01-04
     */
    private List<DeviceEntranceAuthPO> getDeviceEntranceAuthFromDB(String projectId, String userId, Integer authSource){
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource",authSource);

        List<DeviceEntranceAuthPO> deviceEntranceAuthPOSInDB =
                iPropertyDeviceAuthEntranceAuthDao.getUserDeviceEntranceAuth(params);


        return deviceEntranceAuthPOSInDB;
    }

    /**
     * <desc>
     *     获取数据库中指定用户指定项目物业临时权限来源的门禁权限
     * </desc>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param authSource 权限来源 如  DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType()
     * @return 数据库中已有的门禁权限
     * @author zhangs
     * @createDate 2018-01-04
     */
    private List<DeviceEntranceAuthPO> getTempDeviceEntranceAuthFromDB(String projectId, String userId, Integer authSource){
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("tempAuth",authSource);

        List<DeviceEntranceAuthPO> deviceEntranceAuthPOSInDB =
                iPropertyDeviceAuthEntranceAuthDao.getUserTempDeviceEntranceAuth(params);


        return deviceEntranceAuthPOSInDB;
    }


    /**
    * <desc>
    *     将本次选中的设备权限转换为Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>
    * </desc>
    *
    * @param  selectDevices 选中的设备
      * @param  naturalFloors 选中的设备对应的楼层权限列表
    * @return <deviceUnique,floorHexStr>
    * @author LewisLouis
    * @createDate 2018-01-03
    */
    private Map<String,String> convertSelectedElevatorAuthsToMap(String selectDevices,List<String> naturalFloors,String mark){
        List<String> selectDeviceList = new ArrayList<>();
        List<String> selectDevice = Arrays.asList(selectDevices.split(","));
        //移除未选择设备的项
        if ("mark".equals(mark)) {
            for (int floorIndex = 0; floorIndex<selectDevice.size(); floorIndex++){
                if (StringUtils.isNotBlank(selectDevice.get(floorIndex))){
                    selectDeviceList.add(selectDevice.get(floorIndex));
                }
            }
        }else{
            for (int floorIndex = selectDevice.size() - 1; floorIndex>=0; floorIndex--){
                if (StringUtils.isNotBlank(selectDevice.get(floorIndex))){
                    selectDeviceList.add(selectDevice.get(floorIndex));
                }
            }
        }
        Map<String, String> selectedDeviceAuthMap = new HashMap<>();
        //选中电梯设备数量与楼层信息数量一致，前面已经判断
        for (int devIndex = 0; devIndex < selectDeviceList.size(); devIndex ++){
            StringBuffer oneDevfloorBuffer = new StringBuffer(naturalFloors.get(devIndex));
            String oneDevHexfloorAuth = StringHandlerUtil.getAuthCodeBynNturalFloors(StringHandlerUtil.clearComma(oneDevfloorBuffer).toString());
            selectedDeviceAuthMap.put(selectDeviceList.get(devIndex),oneDevHexfloorAuth);
        }
        return selectedDeviceAuthMap;
    }


    /**
     * <desc>
     *     将数据库中设备权限转换为Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>
     * </desc>
     *
     * @param  oldPropertyTmpDeviceElevatorAuthPOS
     * @return <deviceUnique,floorHexStr>
     * @author LewisLouis
     * @createDate 2018-01-03
     */
    private Map<String,String> convertOldTmpElevatorAuthToMap(List<DeviceElevatorAuthPO> oldPropertyTmpDeviceElevatorAuthPOS){
        Map<String, String> oldTmpDeviceAuthMap = new HashMap<>();
        if ((null == oldPropertyTmpDeviceElevatorAuthPOS) || (oldPropertyTmpDeviceElevatorAuthPOS.isEmpty())){
            return oldTmpDeviceAuthMap;
        }
        DeviceElevatorAuthPO oldElevatorAuth = oldPropertyTmpDeviceElevatorAuthPOS.get(0);
        String binDevAuth = oldElevatorAuth.getDeviceAuth();
        String hexfloorAuths = oldElevatorAuth.getFloorAuth();
        List<String> hexfloorAuthList = Arrays.asList(hexfloorAuths.split(","));
        //当前有权限电梯设备对应的楼层权限,有权限电梯设备个数与楼层权限是对应的
        int hexFloorAuthIndex = 0;
        for (int devIndex = 0; devIndex < binDevAuth.length(); devIndex++){
            if (binDevAuth.charAt(devIndex) == PlatformConstants.ELEVATOR_AUTHNUM.charAt(0)){
                String deviceUnique = StringHandlerUtil.getDeviceUniqueId(
                        oldElevatorAuth.getProjectId(),PropertyEquipTypeEnum.ELEVATOR.getType(),String.valueOf(devIndex + 1));
                if (hexFloorAuthIndex > hexfloorAuthList.size()) {
                    LOG.info(String.format("电梯控制器权限数量和楼层权限数量不匹配,%s", JSONObject.toJSONString(oldElevatorAuth)));
                    continue;
                }
                String oneDevHexFloor = hexfloorAuthList.get(hexFloorAuthIndex);
                oldTmpDeviceAuthMap.put(deviceUnique,oneDevHexFloor);
                hexFloorAuthIndex++;
                /*if (hexfloorAuthList.size() > devIndex){
                    String oneDevHexFloor = hexfloorAuthList.get(devIndex);
                    oldTmpDeviceAuthMap.put(deviceUnique,oneDevHexFloor);
                } else{
                    LOG.error(String.format("电梯控制器权限数量和楼层权限数量不匹配,%s", JSONObject.toJSONString(oldElevatorAuth)));
                }*/
            }
        }

        return oldTmpDeviceAuthMap;
    }

    /**
    * <desc>
    *     将设备权限Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>转换为存库对象
    * </desc>
    *
    * @param newTmpElevatorAuthMap 设备权限Map.<deviceUnique,floorHexStr> eg <0000031210001,4000000000000000000000000000>
    * @return 物业临时电梯权限数据库对象
    * @author LewisLouis
    * @createDate 2018-01-03
    */
    private DeviceElevatorAuthPO convertNewTmpElevatorAuthToMapToPO(Map<String,String> newTmpElevatorAuthMap){
        Map<String, String> orderedElevatorAuthMapMap = new TreeMap<>(newTmpElevatorAuthMap);
        //排序后的设备-楼层信息集合
        orderedElevatorAuthMapMap = this.mapSortByKey(orderedElevatorAuthMapMap);
        String binDeviceAuth = StringHandlerUtil.fillString(PlatformConstants.ELEVATOR_NOAUTHNUM,PlatformConstants.ELEVATOR_NOAUTHNUM,PlatformConstants.MAX_ELEVATOR_DEVICEID);
        StringBuffer binDeviceAuthBuffer = new StringBuffer(binDeviceAuth);
        List<String> floorsList = new ArrayList<>();
        for (Map.Entry<String, String> entry : orderedElevatorAuthMapMap.entrySet()) {
            String deviceUnique = entry.getKey();
            Integer devId = StringHandlerUtil.strToIntDef(StringHandlerUtil.copySubStr(deviceUnique,9,4),0);
            //设备在授权设备信息字符串中的位置
            int deviceAuthIndex = devId - 1;
            binDeviceAuthBuffer.setCharAt(deviceAuthIndex, PlatformConstants.ELEVATOR_AUTHNUM.charAt(0));
            String hexFloorsOfOneDev = entry.getValue();
            floorsList.add(hexFloorsOfOneDev);
        }
        String floorsAuth = Joiner.on(",").join(floorsList);
        DeviceElevatorAuthPO deviceElevatorAuthPO = new DeviceElevatorAuthPO();
        deviceElevatorAuthPO.setDeviceAuth(binDeviceAuthBuffer.toString());
        deviceElevatorAuthPO.setFloorAuth(floorsAuth);
        return deviceElevatorAuthPO;

    }


    /**
     * <desc>
     *      保存或更新门禁设备临时权限
     * <desc/>
     *
     * @param loginUserId 用户登录Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param currentDevices 当前页面所有设备唯一码，以英文逗号拼接
     * @param selectDevices 当前页面所有选中设备唯一码，以英文逗号拼接
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveOrUpdateTmpPropertyEntranceAuth(
            String loginUserId,
            String userId,
            String projectId,
            String currentDevices,
            String selectDevices,
            String mark
            ) throws Exception {
        //维护物业临时权限or住户权限组权限
        Integer authSource = DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType();
        if ("mark".equals(mark)) {
            authSource = DeviceAuthEnum.DEVICEAUTH_HOUSEHOLD_ROLE.getType();
        }
        List<DeviceEntranceAuthPO> deviceEntranceAuthPOS =
                this.getTempDeviceEntranceAuthFromDB(projectId,userId,authSource);
        String deviceAuth = null;
        if ((null == deviceEntranceAuthPOS) || (deviceEntranceAuthPOS.isEmpty())) {
            //添加
            //获取授权设备信息
             deviceAuth = this.getDeviceAuthString(selectDevices, PlatformConstants.ENTRANCE_AUTHNUM,
                    PlatformConstants.ENTRANCE_NOAUTHNUM, PlatformConstants.MAX_ENTRANCE_DEVICEID);
             if (StringUtils.isNotBlank(deviceAuth)) {
                 //组装PO
                 DeviceEntranceAuthPO deviceEntranceAuthPO = new DeviceEntranceAuthPO();
                 deviceEntranceAuthPO.setUserId(userId);
                 deviceEntranceAuthPO.setProjectId(projectId);
                 deviceEntranceAuthPO.setValiTime(DateUtil.fomatLongDate("2099-12-31 23:59:59"));
                 deviceEntranceAuthPO.setDeviceAuth(deviceAuth);
                 deviceEntranceAuthPO.setAuthSource(authSource);
                 deviceEntranceAuthPO.setAuthUserId(loginUserId);
                 deviceEntranceAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
                 Date date = new Date();
                 deviceEntranceAuthPO.setCreateTime(date);
                 deviceEntranceAuthPO.setUpdateTime(date);
                 iPropertyDeviceAuthEntranceAuthDao.save(SqlUtil.durableData(deviceEntranceAuthPO, PlatformConstants.TABLE_SAVE));
             }
        } else {
            //更新
            for (DeviceEntranceAuthPO deviceEntranceAuthPO:deviceEntranceAuthPOS) {
                String entranceAuth = deviceEntranceAuthPO.getDeviceAuth();
                if (StringUtils.isNotBlank(entranceAuth)) {
                    //授权设备信息
                    StringBuffer deviceAuthBuffer = new StringBuffer(entranceAuth);

                    //前端页面传输的当前页面所有设备唯一码数组
                    String[] AllDeviceUniques = currentDevices.split(",");

                    for (int index = 0;index < AllDeviceUniques.length;index++) {
                        //前端传输的所有设备中，在需加权部分的做加权处理，其余做除权处理
                        String deviceUnique = AllDeviceUniques[index];
                        //获取设备机号
                        String deviceId = StringHandlerUtil.copySubStr(deviceUnique, 9, 4);
                        //设备在授权设备信息字符串中的位置
                        int positionIndex = Integer.parseInt(deviceId) - 1;
                        if (selectDevices.indexOf(deviceUnique) > -1) {
                            //加权处理
                            deviceAuthBuffer.setCharAt(positionIndex, PlatformConstants.ENTRANCE_AUTHNUM.charAt(0));
                        } else {
                            //除权处理
                            //在授权设备信息字符串中去权
                            deviceAuthBuffer.setCharAt(positionIndex, PlatformConstants.ENTRANCE_NOAUTHNUM.charAt(0));
                        }
                    }
                    deviceAuth = deviceAuthBuffer.toString();
                    //有权限则更新，无则清除数据
                    if (deviceAuth.indexOf(PlatformConstants.ENTRANCE_AUTHNUM) > -1) {
                        deviceEntranceAuthPO.setDeviceAuth(deviceAuth);
                        deviceEntranceAuthPO.setAuthUserId(loginUserId);
                        deviceEntranceAuthPO.setUpdateTime(new Date());
                        iPropertyDeviceAuthEntranceAuthDao.update(deviceEntranceAuthPO);
                    } else {
                        iPropertyDeviceAuthEntranceAuthDao.deleteById(String.valueOf(deviceEntranceAuthPO.getId()));
                    }
                }
            }
        }

        //维护一卡通临时权限
        if ((StringUtils.isNotBlank(deviceAuth)) && (deviceAuth.indexOf(PlatformConstants.ENTRANCE_AUTHNUM) > -1)) {
            //设备授权临时权限时同步更新一卡通权限(如两者有重复权限，去掉临时权限时也去掉一卡通的对应设备权限)
            deviceEntranceAuthPOS = this.getDeviceEntranceAuthFromDB(projectId,userId,DeviceAuthEnum.DEVICEAUTH_SMARTCARD.getType());
            if ((deviceEntranceAuthPOS != null) && (!deviceEntranceAuthPOS.isEmpty())) {
                this.updateSmartCardEntranceAuthByTemp(currentDevices, selectDevices, deviceEntranceAuthPOS);
            }
        }
    }

    /**
     * <desc>
     *      去掉临时门禁权限中与一卡通重合部分的设备权限时，也去掉一卡通中对应的门禁设备权限
     * <desc/>
     *
     * @param currentDevices 当前页面所有设备唯一码，以英文逗号拼接
     * @param selectDevices 当前页面所有选中设备唯一码，以英文逗号拼接
     * @param deviceEntranceAuthPOS 一卡通门禁设备权限数据集
     * @author zhangs
     * @createDate 2017/12/27
     */
    private void updateSmartCardEntranceAuthByTemp(
            /*String loginUserId,
            String userId,
            String projectId,
            Integer authSource,*/
            String currentDevices,
            String selectDevices,
            List<DeviceEntranceAuthPO> deviceEntranceAuthPOS) throws Exception {
        //一卡通门禁设备权限
        DeviceEntranceAuthPO deviceEntranceAuthPO = deviceEntranceAuthPOS.get(0);
        //授权设备信息
        StringBuffer deviceAuthBuffer = new StringBuffer(deviceEntranceAuthPO.getDeviceAuth());
        //前端页面传输的当前页面所有设备唯一码数组
        String[] AllDeviceUniques = currentDevices.split(",");
        //删掉一卡通中属于currentDevices且不属于selectDevices中的设备权限
        for (String deviceUnique:AllDeviceUniques) {
            if ((StringUtils.isNotBlank(selectDevices)) && (selectDevices.contains(deviceUnique))) {
                continue;
            }
            //获取设备机号
            String deviceId = StringHandlerUtil.copySubStr(deviceUnique, 9, 4);
            //设备在授权设备信息字符串中的位置
            int positionIndex = Integer.parseInt(deviceId) - 1;
            //去掉一卡通中属于currentDevices的设备权限
            deviceAuthBuffer.setCharAt(positionIndex, PlatformConstants.ENTRANCE_NOAUTHNUM.charAt(0));
        }
        deviceEntranceAuthPO.setDeviceAuth(deviceAuthBuffer.toString());
        deviceEntranceAuthPO.setUpdateTime(new Date());
        iPropertyDeviceAuthEntranceAuthDao.update(deviceEntranceAuthPO);
    }

    /**
     * <desc>
     *      保存或更新云对讲设备临时权限
     * <desc/>
     *
     * @param loginUserId 用户登录Id
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param currentDevices 当前页面所有设备唯一码，以英文逗号拼接
     * @param selectDevices 当前页面所有选中设备唯一码，以英文逗号拼接
     * @return deviceCloudIntercomAuthPOS 云对讲设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveOrUpdateTmpPropertyCloudIntercomAuth(
            String loginUserId,
            String userId,
            String projectId,
            String currentDevices,
            String selectDevices) throws Exception {

        Integer authSource = DeviceAuthEnum.DEVICEAUTH_PROPERTY_TEMPORARY.getType();
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource", authSource);
        List<DeviceCloudIntercomAuthPO> deviceCloudIntercomAuthPOS =
                iPropertyDeviceAuthCloudIntercomAuthDao.getUserDeviceCloudIntercomAuth(params);

        if ((null == deviceCloudIntercomAuthPOS) || (deviceCloudIntercomAuthPOS.isEmpty())) {
            //添加
            //获取授权设备信息
            String deviceAuth = this.getDeviceAuthString(selectDevices, PlatformConstants.CLOUD_INTERCOM_AUTHNUM,
                    PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM, PlatformConstants.MAX_CLOUD_INTERCOM_DEVICEID);
            if (StringUtils.isNotBlank(deviceAuth)) {
                //组装PO
                DeviceCloudIntercomAuthPO deviceCloudIntercomAuthPO = new DeviceCloudIntercomAuthPO();
                deviceCloudIntercomAuthPO.setUserId(userId);
                deviceCloudIntercomAuthPO.setProjectId(projectId);
                deviceCloudIntercomAuthPO.setValiTime(DateUtil.fomatLongDate("2099-12-31 23:59:59"));
                deviceCloudIntercomAuthPO.setDeviceAuth(deviceAuth);
                deviceCloudIntercomAuthPO.setAuthSource(authSource);
                deviceCloudIntercomAuthPO.setAuthUserId(loginUserId);
                deviceCloudIntercomAuthPO.setStatus(DataStatusEnum.NORMAL.getType());
                Date date = new Date();
                deviceCloudIntercomAuthPO.setCreateTime(date);
                deviceCloudIntercomAuthPO.setUpdateTime(date);
                iPropertyDeviceAuthCloudIntercomAuthDao.save(SqlUtil.durableData(deviceCloudIntercomAuthPO, PlatformConstants.TABLE_SAVE));
            }
        } else {
            //更新
            DeviceCloudIntercomAuthPO deviceCloudIntercomAuthPO = deviceCloudIntercomAuthPOS.get(0);
            String cloudIntercomAuth = deviceCloudIntercomAuthPO.getDeviceAuth();
            if (StringUtils.isNotBlank(cloudIntercomAuth)) {
                //授权设备信息
                StringBuffer deviceCloudIntercomBuffer = new StringBuffer(cloudIntercomAuth);

                //前端页面传输的当前页面所有设备唯一码数组
                String[] AllDeviceUniques = currentDevices.split(",");

                for (int index = 0;index < AllDeviceUniques.length;index++) {
                    //前端传输的所有设备中，在需加权部分的做加权且更新楼层信息处理，其余做除权处理
                    String deviceUnique = AllDeviceUniques[index];
                    //获取设备机号
                    String deviceId = StringHandlerUtil.copySubStr(deviceUnique, 9, 4);
                    //设备在授权设备信息字符串中的位置
                    int positionIndex = Integer.parseInt(deviceId) - 1;
                    if (selectDevices.indexOf(deviceUnique) > -1) {
                        //加权处理
                        deviceCloudIntercomBuffer.setCharAt(positionIndex, PlatformConstants.CLOUD_INTERCOM_AUTHNUM.charAt(0));
                    } else {
                        //除权处理
                        //在授权设备信息字符串中去权
                        deviceCloudIntercomBuffer.setCharAt(positionIndex, PlatformConstants.CLOUD_INTERCOM_NOAUTHNUM.charAt(0));
                    }
                }
                //有云对讲权限则更新，无则清除
                if (deviceCloudIntercomBuffer.indexOf(PlatformConstants.CLOUD_INTERCOM_AUTHNUM) > -1) {
                    deviceCloudIntercomAuthPO.setDeviceAuth(deviceCloudIntercomBuffer.toString());
                    deviceCloudIntercomAuthPO.setAuthUserId(loginUserId);
                    deviceCloudIntercomAuthPO.setUpdateTime(new Date());
                    iPropertyDeviceAuthCloudIntercomAuthDao.update(deviceCloudIntercomAuthPO);
                } else {
                    iPropertyDeviceAuthCloudIntercomAuthDao.deleteById(String.valueOf(deviceCloudIntercomAuthPO.getId()));
                }
            }
        }
    }


    /**
     * <desc>
     *      设备授权-获取用户设备权限
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param deviceType 设备类型
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<AppUserGetDeviceAuthVO> getUserDeviceAuth(String userId, String projectId, String deviceType) throws Exception {
        //由物业授权的权限标记为不可选中即返回给前端时前端无法选中，一卡通的权限标记为可选中
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) || StringUtils.isBlank(deviceType)) {
            return appUserGetDeviceAuthVOS;
        }
        //从数据库中查询
        appUserGetDeviceAuthVOS = this.getDeviceAuth(userId, projectId, deviceType);
        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      获取用户在当前项目中的特定设备类型的设备权限(缓存中获取)
     * <desc/>
     *
     * @param userId 用户Id
     * @param projectId 项目Id
     * @param deviceType 设备类型
     * @return List<AppUserGetDeviceAuthVO> App用户设备权限数据集
     * @author zhangs
     * @createDate 2017/10/10
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<AppUserGetDeviceAuthVO> getDeviceAuthByRedis(String userId, String projectId, String deviceType) {
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = new ArrayList<>();
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(projectId) || StringUtils.isBlank(deviceType)) {
            return appUserGetDeviceAuthVOS;
        }
        //拼接出redis中用的key
        StringBuffer key = new StringBuffer(RedisConstant.REDIS_APP_USER_DEVICE_AUTH_CACHE);
        key.append(userId).append(projectId).append(deviceType);
        //从redis中获取用户设备权限的数据集
        boolean isObtain = true;    //是否获取到了
        String appUserGetDeviceAuthVOStr = redisService.get(key.toString());
        if(StringUtils.isNotBlank(appUserGetDeviceAuthVOStr)) {
            appUserGetDeviceAuthVOS = JSON.parseArray(appUserGetDeviceAuthVOStr, AppUserGetDeviceAuthVO.class);
        } else {
            isObtain = false;
        }
        if(appUserGetDeviceAuthVOS.size() == 0 || !isObtain) {
            appUserGetDeviceAuthVOS = this.getDeviceAuth(userId, projectId, deviceType);
            redisService.set(key.toString(), JSON.toJSONString(appUserGetDeviceAuthVOS));
        }
        return appUserGetDeviceAuthVOS;
    }

    /**
     * <desc>
     *      与旺龙一卡通对接-收集云端变动数据-住户设备权限
     * <desc/>
     *
     * @param projectId 项目Id
     * @param smartCardSyncDataTmpAuthDTOS 与旺龙一卡通对接-住户设备权限临时信息传输对象集
     * @param dataOperType 操作类型。 更新| 删除| 增加
     * @return
     * @author zhangs
     * @createDate 2017/10/10
     */
    private void prepareUserAuthInfoForSyncToSmartCard(
            String projectId,
            List<SmartCardSyncDataTmpAuthDTO> smartCardSyncDataTmpAuthDTOS,
            SmartCardSyncDataOperTypeEnum dataOperType) throws Exception {
        //有数据变动的电梯设备信息集
        String data = JSON.toJSONString(smartCardSyncDataTmpAuthDTOS);
        //数据类型
        SmartCardSyncDataTypeEnum dataType = SmartCardSyncDataTypeEnum.USER_AUTH_DATA;
        //打包
        SmartCardSyncDataPullDTO smartCardSyncDataPullDTO = new SmartCardSyncDataPullDTO(projectId, data, dataOperType, dataType);
        //发送
        JSONObject dataJs = new JSONObject();
        dataJs.put("data",JSONObject.toJSON(smartCardSyncDataPullDTO));
        messageSender.send(RabbitMQConstant.RABBITMQ_SMARTCARD_SAVE_MODIFY_QUEUE,
                JsonUtil.toJSON(dataJs),
                RabbitMQConstant.RABBITMQ_SMARTCARD_SAVE_EXCHANGE,
                RabbitMQConstant.RABBITMQ_SMARTCARD_SAVE_MODIFY_ROUTING_KEY);
    }


    /**
     * <desc>
     *      查询待刷新权限的地址对象集
     * <desc/>
     * @param  params 查询参数
     * @return  查询到受影响地址集合
     * @author Biao.R
     * @createDate 2018/2/7
     */
    @Override
    public List<TimeTaskAuthDeviceAddressInfoPO> getNotFreshAddrByParams(Map<String, Object> params) {
        return iTimeTaskAuthDeviceAddressInfoDao.getNotFreshAddrByParams(params);
    }

    /**
     * <desc>
     *      获取缓存中标记设备地址变更刷新用户权限定时任务执行状态
     * <desc/>
     * @param
     * @return boolean
     * @author Biao.R
     * @createDate 2018/2/7
     */
    @Override
    public boolean getDeviceAuthTimeTaskExexuterStatus() {
        String isWorking = redisService.get(RedisConstant.FRESH_DEVICEAUTH_TIMEDTASK_EXECUTER_STATUS);
        if (StringHandlerUtil.compareStrWithOutEmpty("true", isWorking)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * <desc>
     *      在缓存中标记设备地址变更刷新用户权限定时任务执行状态
     * <desc/>
     * @param  isWorking  定时任务执行状态(true:正在执行|false:未执行)
     * @return
     * @author Biao.R
     * @createDate 2018/2/7
     */
    @Override
    public void updateDeviceAuthTimeTaskExexuterStatus(boolean isWorking) {
        redisService.set(RedisConstant.FRESH_DEVICEAUTH_TIMEDTASK_EXECUTER_STATUS, String.valueOf(isWorking));
    }

    /**
     * <desc>
     *      定时任务刷新用户权限
     * <desc/>
     * @param   userDeviceAuthAddreddDTOS  地址信息集
     * @param   authSource  权限来源
     * @param   handlerTime  执行时间
     * @return  定时任务表被执行的个数
     * @author Biao.R
     * @createDate 2018/2/8
     */
    @Override
    public Integer updateAddrUserAuthByTimeTask(List<UserDeviceAuthAddreddDTO> userDeviceAuthAddreddDTOS, Integer authSource, String handlerTime) {
        try {
            this.saveUserAuthByAddr(userDeviceAuthAddreddDTOS,authSource);
            Date updateTime = new Date();
            return iTimeTaskAuthDeviceAddressInfoDao.updateCreateTimeBefore(handlerTime,updateTime);
        } catch (Exception e) {
            throw new DataAccessException("【定时任务处理设备地址变更刷新用户权限异常】",e);
        }
    }

    /**
     * <desc>
     *      查询拥有该设备权限的userId
     * <desc/>
     * @param  deviceUnique 设备唯一码
     * @return 拥有该设备权限的userId集合
     * @author Biao.R
     * @createDate 2018/2/8
     */
    @Override
    public List<String> getAuthUserIdByDeviceUnique(String deviceUnique) {
        if (StringUtils.isEmpty(deviceUnique) || !deviceUnique.matches("[0-9]{13}")) {
            return null;
        }
        String deviceType = deviceUnique.substring(8, 9);
        if (!deviceType.matches("1|2|3")) {
            return null;
        }
        String projectId = deviceUnique.substring(0, 8);
        String deviceId = deviceUnique.substring(9, 13).replaceAll("^(0+)", "");
        return iPropertyDeviceAuthElevatorAuthDao.getAuthUserIdByDeviceUnique(projectId, deviceType, deviceId);
    }

    /**
     * <desc>
     *      通知APP服务清缓存
     * <desc/>
     * @param   list
     * @return
     * @author Juguang.S
     * @createDate 2018/4/17
     */
    public void noticeOtherServiceRedisBySamrtCard(List<EquipAuthUserGetVO> list){

        //权限变更通知其他模块更新相应缓存redis
        Map<String, Object> param = new HashMap<>();
        if(list.size()>50){
            param.put("projectId", list.get(0).getProjectId());

        }else{
            param.put("userIdList",list);
        }
        try {
            messageSender.send(RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_QUEUE,
                    JSON.toJSONString(param), RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_KEY);
        } catch (Exception e) {
            throw new DataAccessException("【清理一卡通用户缓存失败】",e);
        }

    }

    /**
     * <desc>
     *     执行调度smart_card_face_pull_cloud_info表中的大于允许同步时间的数据推送至人脸识别系统
     * </desc>
     *
     * @author Juguang.S
     * @createDate 2019/07/06
     */
    @Override
    public void timeTaskPushSamrtCardFace(){
        try {
        //首先查出大于允许同步时间且没有被同步过的数据
            //修改当前日期前一天的同步状态
            iTimeTaskAuthDeviceAddressInfoDao.updateExpiredSyncData();
            List<SmartCardFaceTimePullInfoPO> infoList = iTimeTaskAuthDeviceAddressInfoDao.getAllowSyncData();
            if(!infoList.isEmpty() && infoList!=null){
                for(SmartCardFaceTimePullInfoPO pullInfoPO : infoList){

                    List<Map<String, Object>> auths = new ArrayList<>();
                    String deviceUniqueStr = pullInfoPO.getDeviceUniqueInfo();
                    String status = pullInfoPO.getStatus().toString();
                    Splitter split = Splitter.on(',').trimResults().omitEmptyStrings(); // 去前后空格&&去空string
                    //为了避免下发重复增量，现进行去重处理
                    Set<String> sets = new HashSet<>();
                    for (String userId : split.splitToList(pullInfoPO.getUserIdInfo())) {
                        sets.add(userId);
                    }

                    for (String userId : sets) {
                        //查询用户在项目下的标签及常用楼层信息
                        Map<String,Object> resultMap = iPadFaceSyncDataServiceDao.getUserLabelInfo(userId, pullInfoPO.getProjectId());
                        List<Map<String, Object>> sysAuths = new ArrayList<>();
                        Map<String, Object> auth = new HashMap<>();
                        auth.put("userId", userId);
                        auth.put("id",userId);
                        //如果userId不以V_为前缀则代表为住户 否则为访客
                        if(userId.startsWith("V_")){
                            userId = iSmartCardFaceDao.getUserIdByVFaceId(userId,"");
                        }

                        //门禁
                        List<AppDoorDevicesVO> doors = iAppDeviceService.getDoorDevices(userId, pullInfoPO.getProjectId(), 0);
                        for (AppDoorDevicesVO door : doors) {
                            Map<String, Object> sysAuth = new HashMap<>();
                            sysAuth.put("deviceType", 2);
                            sysAuth.put("auth", "8");
                            sysAuth.put("deviceUnique", door.getDeviceUnique());
                            if((StringUtils.isNotBlank(door.getDoorType()) && door.getDoorType().contains("3")) ||
                                    (StringUtils.isNotBlank(door.getDoorType()) && door.getDoorType().contains("1,3"))){
                                sysAuth.put("isWippen","1");
                            }else{
                                sysAuth.put("isWippen","0");
                            }
                            sysAuths.add(sysAuth);
                        }
                        //电梯
                        List<AppFloorDevicesVO> floorsList = iAppDeviceService.getFloorDevicesByNoStardard(userId, pullInfoPO.getProjectId(), 0);
                        for (AppFloorDevicesVO floorInfo : floorsList) {
                            if(iSmartCardFaceService.isCloudElevator(floorInfo.getDeviceUnique())>0){
                                Map<String, Object> sysAuth = new HashMap<>();
                                sysAuth.put("deviceType", 1);
                                sysAuth.put("mainFloor",floorInfo.getMainFloor());
                                sysAuth.put("backFloor",floorInfo.getBackFloor());
                                sysAuth.put("auth", floorInfo.getLiveFloor());
                                sysAuth.put("deviceUnique", floorInfo.getDeviceUnique());
                                //处理用户在电梯设备中所设置的常用楼层
                                if(resultMap!=null && resultMap.get("userAllCommonFloor")!=null && StringUtils.isNotBlank(resultMap.get("userAllCommonFloor").toString())){
                                    Map<String,Object> commanFloors = JsonUtil.toObject(resultMap.get("userAllCommonFloor").toString(),HashMap.class);
                                    if(commanFloors.containsKey(floorInfo.getDeviceUnique())){
                                        if(StringUtils.isNotEmpty(floorInfo.getLiveFloor()) && Arrays.asList(floorInfo.getLiveFloor().split(",")).contains(commanFloors.get(floorInfo.getDeviceUnique()).toString())){
                                            sysAuth.put("commonFloor", commanFloors.get(floorInfo.getDeviceUnique()).toString());
                                        }else{
                                            sysAuth.put("commonFloor", "");
                                        }
                                    }else{
                                        sysAuth.put("commonFloor", "");
                                    }
                                }else{
                                    sysAuth.put("commonFloor", "");
                                }
                                sysAuths.add(sysAuth);
                            }
                        }
                        auth.put("sysAuths", sysAuths);
                        auths.add(auth);
                    }
                    //如果是设备启用禁用触发的，则需将设备下的访客信息给拼接进来
                    if(StringUtils.isNotEmpty(deviceUniqueStr) && StringUtils.isNotEmpty(status)){
                        auths = iSmartCardFaceService.saveVisitorInfo(deviceUniqueStr,status,auths, pullInfoPO.getProjectId());
                    }
                    if(auths!=null && !auths.isEmpty() && auths.size()>0){
                        iSmartCardFaceService.pushUserAuthChange(JsonUtil.toJSON(auths), pullInfoPO.getProjectId());
                    }

                    //处理后需将此条数据的状态改为已处理
                    pullInfoPO.setSyncStatus(2);
                    pullInfoPO.setUpdateTime(new Date());
                    iTimeTaskAuthDeviceAddressInfoDao.update(SqlUtil.durableData(pullInfoPO,PlatformConstants.TABLE_UPDATE));
                }
            }
        } catch (Exception e) {
            LOG.error("【执行调度smart_card_face_pull_cloud_info表中的大于允许同步时间的数据推送至人脸识别系统】:处理异常", e);
        }
    }

    /**
     * <desc>
     *      获取用户有权限的设备分页列表
     * </desc>
     *
     * @param  propertyEquipAuthGetDTO 查询参数DTO
     * @return 用户有权限的设备分页列表
     * @Author Zhu.yj
     * @createDate  2021/4/21
     */
    @Override
    public Page<PropertyEquipSimpleVO> getUserHaveAuthDevice(PropertyEquipAuthGetDTO propertyEquipAuthGetDTO) throws Exception {

        Page<PropertyEquipSimpleVO> page = new Page<>();
        //找出用户所有的设备的权限列表
        List<AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOS = this.getDeviceAuth(propertyEquipAuthGetDTO.getUserId(),
                propertyEquipAuthGetDTO.getProjectId(), propertyEquipAuthGetDTO.getDeviceType().toString());
        if (appUserGetDeviceAuthVOS == null || appUserGetDeviceAuthVOS.isEmpty()){
            return page;
        }
        List<String> deviceIdList = new ArrayList<>();
        Map<String, AppUserGetDeviceAuthVO> appUserGetDeviceAuthVOMap = new HashMap<>();
        for (AppUserGetDeviceAuthVO appUserGetDeviceAuthVO : appUserGetDeviceAuthVOS){
            deviceIdList.add(appUserGetDeviceAuthVO.getDeviceUnique());
            appUserGetDeviceAuthVOMap.put(appUserGetDeviceAuthVO.getDeviceUnique(), appUserGetDeviceAuthVO);
        }
        //电梯
        if(DEVICEAUTH_DEVICETYPE_ELEVATOR == propertyEquipAuthGetDTO.getDeviceType()){
            //找出电梯绑定的群控器id列表，未绑群控器时则找出电梯id列表
            List<String> controllerDeviceList= iPropertyDeviceAuthElevatorAuthDao.getControllerDeviceUniqueList(deviceIdList);
            propertyEquipAuthGetDTO.setDeviceUniqueList(controllerDeviceList);
            page = iPropertyEquipService.getUserEquipAuthByPage(propertyEquipAuthGetDTO);
            for (PropertyEquipSimpleVO equipSimpleVO : page.getRows()){
                AppUserGetDeviceAuthVO appUserGetDeviceAuthVO = appUserGetDeviceAuthVOMap.get(equipSimpleVO.getDeviceUnique());
                if (appUserGetDeviceAuthVO != null){
                    //这里直接将用户的权限楼层转换成字符串返回前端展示

                    //用户的地址权限
                    List<String> addressFloor = StringHandlerUtil.splitStringList(appUserGetDeviceAuthVO.getLogicalFloor());
                    //用户的临时权限
                    List<String> tmpFloor = StringHandlerUtil.splitStringList(appUserGetDeviceAuthVO.getTempFloor());
                    addressFloor.addAll(tmpFloor);
                    //楼层去重
                    Set<String> floorSet = new TreeSet<>(addressFloor);

                    equipSimpleVO.setFloors(floorSet.toString());
                }
            }
        }else {
            //门禁或云对讲
            propertyEquipAuthGetDTO.setDeviceUniqueList(deviceIdList);
            propertyEquipAuthGetDTO.setMark("mark");
            page = iPropertyEquipService.getUserEquipAuthByPage(propertyEquipAuthGetDTO);
        }
        return page;
    }

    /**
     * <desc>
     *      删除用户电梯和门禁的分组权限
     * </desc>
     *
     * @param projectId
     * @param userId
     * @return
     * @Author Zhu.yj
     * @createDate  2021/5/11
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Integer deleteUserDeviceAuth(String projectId, String userId) throws Exception {

        //删除用户电梯分组权限
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("userId", userId);
        params.put("authSource", DeviceAuthEnum.DEVICEAUTH_HOUSEHOLD_ROLE.getType());
        iPropertyDeviceAuthElevatorAuthDao.deleteElevatorAuth(params);
        //删除用户门禁权限
        iPropertyDeviceAuthEntranceAuthDao.deleteEntranceAuth(params);
        return 1;
    }

}
